package com.youlu.campus.web.ca.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.google.common.collect.Lists;
import com.kuaidi100.sdk.response.SubscribePushData;
import com.mongodb.client.result.UpdateResult;
import com.youlu.campus.base.exception.BusinessException;
import com.youlu.campus.base.order.GoodsInfo;
import com.youlu.campus.base.order.enums.OrderPayTypeEnum;
import com.youlu.campus.entity.ActivityInfo;
import com.youlu.campus.entity.ActivityUserRecord;
import com.youlu.campus.entity.CaInfo;
import com.youlu.campus.entity.CaMaterialConfig;
import com.youlu.campus.entity.MemberShipInfo;
import com.youlu.campus.entity.OOrderInfo;
import com.youlu.campus.entity.OrderInfo;
import com.youlu.campus.entity.OrderInfoTip;
import com.youlu.campus.entity.PayButtonConfigPage;
import com.youlu.campus.entity.PayConfigPage;
import com.youlu.campus.entity.PlatformConfig;
import com.youlu.campus.entity.PostageTemplate;
import com.youlu.campus.entity.PostageTemplateDetail;
import com.youlu.campus.entity.UniversityInfo;
import com.youlu.campus.entity.UserActivityReward;
import com.youlu.campus.entity.UserCaInfo;
import com.youlu.campus.entity.UserCaRecord;
import com.youlu.campus.entity.UserInfoExtend;
import com.youlu.campus.entity.UserMemberShipInfo;
import com.youlu.campus.entity.UserPO;
import com.youlu.campus.entity.VO.PlaceOrderReq;
import com.youlu.campus.entity.VO.req.ItemCheckStockReq;
import com.youlu.campus.entity.VO.req.ItemInfoReq;
import com.youlu.campus.entity.VO.req.MyCaInfoVO;
import com.youlu.campus.entity.VO.req.OrderConfirmComputePriceReq;
import com.youlu.campus.entity.VO.req.OrderInfoQueryVO;
import com.youlu.campus.entity.VO.req.PlaceOrderV2VO;
import com.youlu.campus.entity.VO.req.PlaceOrderVO;
import com.youlu.campus.entity.VO.req.ReceiveCaVO;
import com.youlu.campus.entity.VO.req.UserCaInfoQueryVO;
import com.youlu.campus.entity.VO.res.OrderConfirmComputePriceRes;
import com.youlu.campus.entity.WechatConfigInfo;
import com.youlu.campus.entity.WechatMerchantConfig;
import com.youlu.campus.entity.WechatPayCache;
import com.youlu.campus.entity.ca.GiftCaInfo;
import com.youlu.campus.entity.card.entity.VipGoods;
import com.youlu.campus.entity.card.vo.VipRedeemCodeVo;
import com.youlu.campus.entity.course.vo.UserActivityDeductionVo;
import com.youlu.campus.entity.domain.ActivityRewadDomain;
import com.youlu.campus.entity.domain.WechatH5PayConfigDomain;
import com.youlu.campus.service.activity.ActivityService;
import com.youlu.campus.service.activity.impl.ActivityPayConfigService;
import com.youlu.campus.service.activity.impl.PlatformOtherActivityService;
import com.youlu.campus.service.ca.CaMaterialConfigService;
import com.youlu.campus.service.cache.CacheActivityService;
import com.youlu.campus.service.cache.CacheCaInfoService;
import com.youlu.campus.service.cache.CacheOrderService;
import com.youlu.campus.service.card.TsCardService;
import com.youlu.campus.service.course.CalLeaveDayService;
import com.youlu.campus.service.course.UserActivityDeductionService;
import com.youlu.campus.service.notify.KuaiDi100Service;
import com.youlu.campus.service.order.OrderInfoTipService;
import com.youlu.campus.service.pay.PayV2Service;
import com.youlu.campus.service.pay.UserPurchaseCaService;
import com.youlu.campus.service.platform.PlatformConfigService;
import com.youlu.campus.service.postage.PostageTemplateService;
import com.youlu.campus.service.university.UniversityInfoService;
import com.youlu.campus.service.visitor.UserInfoExtendService;
import com.youlu.campus.service.visitor.VisitorUserService;
import com.youlu.campus.service.wechat.WechatConfigInfoService;
import com.youlu.campus.service.wechat.WechatMerchantConfigService;
import com.youlu.campus.service.wechatpay.WechatPayCacheService;
import com.youlu.campus.web.ca.dto.MyCaInfoDTO;
import com.youlu.campus.web.ca.service.UserCaInfoService;
import com.youlu.campus.web.common.base.RequestContext;
import com.youlu.campus.web.order.entity.OrderPO;
import com.youlu.campus.web.order.service.OrderBaseService;
import com.yuelin.infrastructure.quantum.common.QResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
public class UserCaInfoServiceImpl extends OrderBaseService implements UserCaInfoService {
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private StringRedisTemplate orderRedisTemplate;
    @Autowired
    private WechatPayCacheService wechatPayCacheService;
    @Value("${campus.memberShipNum:1}")
    private Integer memberShipNum;
    final public static String payCache = "luyou.pay-cache";
    @Autowired
    private ActivityService activityService;

    @Autowired
    private PlatformOtherActivityService platformOtherActivityService;

    @Autowired
    private CacheActivityService cacheActivityService;

    @Autowired
    private CacheCaInfoService cacheCaInfoService;

    @Autowired
    private CacheOrderService cacheOrderService;
    @Autowired
    private OrderInfoTipService orderInfoTipService;
    @Autowired
    private VisitorUserService visitorUserService;
    @Autowired
    private WechatConfigInfoService wechatConfigInfoService;
    @Autowired
    private WechatMerchantConfigService wechatMerchantConfigService;
    @Autowired
    private PostageTemplateService postageTemplateService;
    @Autowired
    private ActivityPayConfigService activityPayConfigService;
    @Autowired
    private TsCardService tsCardService;
    @Lazy
    @Autowired
    private UniversityInfoService universityInfoService;
    @Lazy
    @Autowired
    private UserPurchaseCaService userPurchaseCaService;


    public final static String USER_ORDER_PAY = "campus:order:orderNo:%s";

    @Autowired
    private PlatformConfigService platformConfigService;

    @Autowired
    private UserInfoExtendService userInfoExtendService;

    @Resource(name = "masterMongoTemplate")
    private MongoTemplate masterMongoTemplate;

    @Autowired
    private CalLeaveDayService calLeaveDayService;

    @Autowired
    private CaMaterialConfigService caMaterialConfigService;

    @Lazy
    @Autowired
    private KuaiDi100Service kuaiDi100Service;

    @Autowired
    private UserActivityDeductionService userActivityDeductionService;
    @Lazy
    @Autowired
    private PayV2Service payV2Service;

    @Override
    public Page<UserCaInfo> list(UserCaInfoQueryVO req) {
        log.info(":>>> 开始获取用户证书列表:{}", JSON.toJSONString(req));
        if (Objects.isNull(req)) {
            req = new UserCaInfoQueryVO();
        }
        Query query = new Query();
        if (StringUtils.isNotBlank(req.getUserId())) {
            query.addCriteria(Criteria.where("userId").is(req.getUserId()));
        }
        if (Objects.nonNull(req.getMaterial())) {
            query.addCriteria(Criteria.where("material").is(req.getMaterial()));
        }
//        if (Objects.nonNull(req.getCaStatus())) {
//            query.addCriteria(Criteria.where("caStatus").is(req.getCaStatus()).and("caStatus").ne(0));
//        }
        query.addCriteria(Criteria.where("caStatus").ne(0));
        long count = mongoTemplate.count(query, UserCaInfo.class);
        PageRequest pageRequest = PageRequest.of(req.getPage() - 1, req.getPageSize());
//        query.with(new Sort(Sort.Direction.DESC, "createdTime"));
        Sort sort = Sort.by(Sort.Direction.DESC, "createdTime");
        query.with(sort);
        List<UserCaInfo> result = new ArrayList<>();
        List<UserCaInfo> infos = mongoTemplate.find(query.with(pageRequest), UserCaInfo.class);
        if (!CollectionUtils.isEmpty(infos)) {
            for (UserCaInfo userCaInfo : infos) {
                if (StringUtils.isNotBlank(userCaInfo.getCaInfoId())) {
                    Query query1 = new Query().addCriteria(Criteria.where("id").is(userCaInfo.getCaInfoId()));
                    CaInfo caInfo = mongoTemplate.findOne(query1, CaInfo.class);
                    if (Objects.nonNull(caInfo)) {
                        userCaInfo.setCaInfo(caInfo);
                        result.add(userCaInfo);
                    } else {
                        log.error(":>>> 用户证书:{},证书:{} 数据不存在", userCaInfo.getId(), userCaInfo.getCaInfoId());
                    }
                } else {
                    log.error(":>>> 用户证书:{},证书ID为空", userCaInfo.getId());
                }
            }
        }
        log.info(":>>> 返回的用户证书信息为:{}", result.size());
        return PageableExecutionUtils.getPage(result, pageRequest, () -> count);
    }

    @Override
    public UserCaInfo receiveCa(ReceiveCaVO req) {
        log.info(":>>> 开始领取证书:{}", JSON.toJSONString(req));
        if (Objects.isNull(req) || StringUtils.isBlank(req.getUserCaInfoId()) || Objects.isNull(req.getMaterial())) {
            log.error(":>>> 领取证书错误:参数错误");
            throw new BusinessException("领取证书错误:参数错误");
        }
        Query query = new Query().addCriteria(Criteria.where("id").is(req.getUserCaInfoId()));
        UserCaInfo userCaInfo = mongoTemplate.findOne(query, UserCaInfo.class);
        if (Objects.isNull(userCaInfo)) {
            log.error(":>>> 领取证书错误:证书不存在");
            throw new BusinessException("领取证书错误:证书不存在");
        }
        Date date = new Date();
        /**
         * 证书材质,0:电子,1:纸质
         */
        switch (req.getMaterial()) {
            case 0:
                userCaInfo.setReceived(true);
                userCaInfo.setReceiveTime(date);
                userCaInfo.setUpdatedTime(date);
                // 获取电子版盖章
                userCaInfo = mongoTemplate.save(userCaInfo);
                return userCaInfo;
            case 1:
                // 检查地址
                if (Objects.isNull(req.getAddressInfo())) {
                    log.error(":>>> 领取纸质证书错误:地址信息错误");
                    throw new BusinessException("领取纸质证书错误:地址信息错误");
                }
                // 纸质版需要检查是否领取
                Query queryCa = new Query().addCriteria(Criteria.where("userId").is(userCaInfo.getUserId()).and("caInfo.id").is(userCaInfo.getCaInfo().getId()).and("material").is(1));
                UserCaInfo userCaInfoExist = mongoTemplate.findOne(queryCa, UserCaInfo.class);
                if (Objects.isNull(userCaInfoExist)) {
                    userCaInfoExist = new UserCaInfo();
                    BeanUtils.copyProperties(userCaInfo, userCaInfoExist);
                    userCaInfoExist.setId(null);
                    userCaInfoExist.setCreatedTime(date);
                    userCaInfoExist.setMaterial(1);
                    userCaInfoExist.setReceived(false);
                    userCaInfoExist.setReceiveTime(null);
                    userCaInfoExist.setAddressInfo(req.getAddressInfo());
                    // goodsCode对应证书编码
                    String orderNo = userCaInfoExist.getCertificateNo() + this.formatDate(new Date(), "yyyyMMddHHmmssSSS") + (long) (Math.random() * (1000));
                    userCaInfoExist.setOrderNo(orderNo);
                    // 待支付
                    userCaInfoExist.setCaStatus(0);
                    userCaInfoExist = mongoTemplate.save(userCaInfo);
                    // TODO: 设置支付缓存
                    return userCaInfoExist;
                }
                return userCaInfoExist;
            default:
                break;

        }
        return null;
    }

    @Override
    public UserCaInfo getCaDetail(String id, String userId) {
        log.info(":>>> 开始获取用户证书详情:{}", id);
        if (StringUtils.isBlank(id)) {
            log.error(":>>> 获取证书详情错误:参数错误");
            throw new BusinessException("获取证书详情错误:参数错误");
        }
        Query q = new Query().addCriteria(Criteria.where("id").is(id));
        UserCaInfo userCaInfo = mongoTemplate.findOne(q, UserCaInfo.class);
        if (Objects.isNull(userCaInfo)) {
            log.error(":>>> 获取证书详情错误:用户未下单");
            throw new BusinessException("用户未下单");
        }
        if (StringUtils.isBlank(userCaInfo.getCaInfoId())) {
            log.error(":>>> 获取证书详情错误:");
            throw new BusinessException("用户未下单");
        }
        Query query = new Query().addCriteria(Criteria.where("id").is(userCaInfo.getCaInfoId()));
        CaInfo caInfo = mongoTemplate.findOne(query, CaInfo.class);
        userCaInfo.setCaInfo(caInfo);
        // 计算支付类型、和支付费用
        Query query1 = new Query().addCriteria(Criteria.where("id").is(userId));
        UserPO user = mongoTemplate.findOne(query1, UserPO.class);
        if (Objects.isNull(user)) {
            log.error(":>>> 用户不存在:{}", user);
            throw new BusinessException("用户不存在");
        }

        if (Boolean.TRUE.equals(user.getMemberShiped()) && Objects.nonNull(user.getRemainedNum()) && (user.getRemainedNum() > 1)) {
            userCaInfo.setPrice(0);
            userCaInfo.setPayFeeType("0");
            userCaInfo.setPayDesc(String.format("已经开通会员，免费领取，还可领取%d次", (user.getRemainedNum() - 1)));
        } else {
            userCaInfo.setPayFeeType("1");
            userCaInfo.setPrice(caInfo.getPrice());
            userCaInfo.setPayDesc("微信支付");
        }
        userCaInfo.setGoodsCode(caInfo.getGoodsCode());

        return userCaInfo;
    }

    /**
     * 下单
     *
     * @return
     */
    @Override
    public Map<String, String> placeOrder(UserCaInfo req) {
        log.info(":>>> 下单 userId {} req {}", RequestContext.getUserId(), JSON.toJSONString(req));
        if (StringUtils.isBlank(req.getId()) || StringUtils.isBlank(req.getGoodsCode()) || StringUtils.isBlank(req.getPayFeeType()) || Objects.isNull(req.getPrice()) || StringUtils.isBlank(req.getName()) || StringUtils.isBlank(req.getMobile()) || StringUtils.isBlank(req.getProvince()) || StringUtils.isBlank(req.getCity()) || StringUtils.isBlank(req.getArea()) || StringUtils.isBlank(req.getAddress())) {
            log.error(":>>> 支付参数错误");
            throw new BusinessException("支付参数错误");
        }
        UserPO userPO = RequestContext.getCurUser();
        Query query = new Query().addCriteria(Criteria.where("id").is(req.getId()));
        UserCaInfo userCaInfo = mongoTemplate.findOne(query, UserCaInfo.class);
        if (Objects.isNull(userCaInfo)) {
            log.error(":.>> 用户证书不存在:{}", req.getId());
            throw new BusinessException("用户证书不存在");
        }
        String orderNo = "";
        if (StringUtils.isNotBlank(userCaInfo.getOrderNo())) {
            orderNo = userCaInfo.getOrderNo();
        }
        if (StringUtils.isBlank(orderNo)) {
            // goodsCode对应证书编码
            orderNo = super.generateOrderNo("证书");
            userCaInfo.setOrderNo(orderNo);
            mongoTemplate.save(userCaInfo);
        }
        if (super.resubmit(3L, RequestContext.getUserId(), orderNo)) {
            log.info(":>>> 有已经待支付的订单,请不要重复支付");
            throw new BusinessException("请勿重复发起支付~");
        }
        req.setOrderNo(orderNo);
        // 0:会员支付,1:现金支付
        switch (req.getPayFeeType()) {
            case "0":
                req.setUpdatedTime(new Date());
                req.setCaStatus(1);
                mongoTemplate.save(req);
                Query queryUser = new Query().addCriteria(Criteria.where("id").is(req.getUserId()));
                // 更新会员权益的次数
                if (Objects.nonNull(userPO) && Boolean.TRUE.equals(userPO.getMemberShiped())) {
                    if (Objects.nonNull(userPO.getRemainedNum()) && userPO.getRemainedNum() > 1) {
                        Update update = new Update();
                        update.inc("remainedNum", -1);
                        mongoTemplate.updateFirst(queryUser, update, UserPO.class);
                        // 扣减权益次数
                    } else {
                        // 设置会员过期
                        Update update = new Update();
                        update.set("remainedNum", 0);
                        update.set("memberShiped", false);
                        update.set("expiredTime", new Date());
                        mongoTemplate.updateFirst(queryUser, update, UserPO.class);
                    }
                }
                log.info(":>>> 订单为会员权益支付,扣减支付次数,剩余次数为");
                HashMap<String, String> re = new HashMap<>();
                re.put("payFeeType", "0");
                re.put("price", "0");
                re.put("payDesc", "已经开通会员，免费领取，还可领取3次");
                re.put("orderNo", orderNo);
                log.info(":>>> 会员支付参数为:{}", JSON.toJSONString(re));
                return re;
            case "1":
                //获取订单信息
                PlaceOrderReq req1 = new PlaceOrderReq();
                req1.setUserCaInfoId(req.getId());
                req1.setClientIp(req.getClientIp());
                // 自主下单
                req1.setSource(1);
                req1.setPrice(req.getPrice());
                req1.setOrderNo(orderNo);
                req1.setPrice(req.getPrice());
                OrderPO orderPO = this.saveUserCaOrder(RequestContext.getCurUser(), req1);
                orderPO.setTransactionId(orderNo);
                orderPO.setOrderNo(orderNo);
                orderPO.setOpenId(RequestContext.getCurUser().getOpenId());
                orderPO.setPlatform(RequestContext.getCurPlatform());
                Map<String, String> result = new HashMap<>();
                //获取预支付参数

                QResult<Map<String, String>> uniOrderResult = super.getUniOrderResult(orderPO);
                log.info(":>>> 获取微信预支付参数结果为:{}", JSON.toJSONString(uniOrderResult));
                // 支付成功
                if (uniOrderResult.code == 0) {
                    result = uniOrderResult.data;
                    WechatPayCache cache = new WechatPayCache();
                    cache.setOrderNo(orderNo);
                    cache.setType("oid");
                    cache.setBizType("ca");
                    cache.setStatus(Boolean.FALSE);
                    cache.setCreatedTime(new Date());
                    wechatPayCacheService.create(cache);
                } else {
                    log.info("placeOrder applyReq {} error msg {}", req, uniOrderResult.msg);
                }
                result.put("payFeeType", "1");
                result.put("payDesc", "微信支付");
                log.info(":>>> 微信支付参数为:{}", JSON.toJSONString(result));
                if ("wechat-h5".equals(orderPO.getPlatform())) {
                    log.info(":>>> 平台是wechat-h5,设置JS SDK配置");
                    WechatH5PayConfigDomain config = activityService.getPayConfig(userPO, req.getUrl(), orderPO.getNonceStr(), orderPO.getTimestampStr());
                    result.put("appId", config.getAppId());
                    result.put("signature", config.getSignature());
                    result.put("nonceStr", config.getNonceStr());
                    result.put("timeStamp", config.getTimestamp());
                    result.put("jsApiList", JSON.toJSONString(config.getJsApiList()));
                }
                // TODO:更新订单状态:等待回调
                log.info(":>>> 微信支付参数为:{}", JSON.toJSONString(result));
                return result;

            default:
                return null;
        }

    }

    @Override
    public Map<String, String> placeOrder(ActivityRewadDomain req) {
        log.info(":>>> 领取奖励下单:{}", JSON.toJSONString(req));
        if (Objects.isNull(req) || StringUtils.isBlank(req.getName()) || StringUtils.isBlank(req.getMobile()) || StringUtils.isBlank(req.getProvince()) || StringUtils.isBlank(req.getAddress()) || Objects.isNull(req.getChoicedMemberShip())) {
            log.error(":>>> 用户下单参数错误");
            throw new BusinessException("用户下单参数错误");
        }
        Date date = new Date();
        // 检查领取时间
        checkPlaceOrderTime(req.getActivityId(), date);
        // 已经发布的会员卡
        Query queryMemberShip = new Query().addCriteria(Criteria.where("status").is(1));

        MemberShipInfo memberShipInfo = mongoTemplate.findOne(queryMemberShip, MemberShipInfo.class);
        log.info(":>>> 已经发布的会员卡:{},价格为:{}", memberShipInfo.getName(), memberShipInfo.getPrice());

//        Query queryU = new Query().addCriteria(Criteria.where("id").is(req.getUserId()));
        UserPO userPO = RequestContext.getCurUser();
        log.info(":>>>  用户开通会员:{},剩余的抵扣次数:{}", userPO.getMemberShiped(), userPO.getRemainedNum());
        List<CaInfo> caInfos = new ArrayList<>();
        caInfos.addAll(req.getCaInfos());
        caInfos.addAll(req.getOtherCaInfos());
        Integer userCanPayNum = 0;
        if (Boolean.TRUE.equals(userPO.getMemberShiped())) {
            userCanPayNum = userPO.getRemainedNum() == null ? memberShipNum : userPO.getRemainedNum();
        }
        Integer cumputedPrice = this.computeOrderPrice(req.getChoicedMemberShip(), userPO.getMemberShiped(), memberShipInfo.getPayNum(), userCanPayNum, req.getUserId(), memberShipInfo.getPrice(), caInfos);
        if (cumputedPrice.compareTo(req.getPrice()) != 0) {
            log.error(":>>> 价格计算错误后台价格:{},提交的价格:{}", cumputedPrice, req.getPrice());
            throw new BusinessException("价格计算错误");
        }
        int remainNum = 0;
        String pOrderNo = super.generateOrderNo("20");
        log.info(":>>> 生成的父订单号:{}", pOrderNo);
        String memberShipId = "";
        if (Boolean.TRUE.equals(req.getChoicedMemberShip())) {
            log.info(":>>> 用户选择的会员卡:{}", req.getUserId());
            // 本身不是会员
            if (!Boolean.TRUE.equals(userPO.getMemberShiped())) {
                UserMemberShipInfo userMemberShipInfo = new UserMemberShipInfo();
                userMemberShipInfo.setPayFee(memberShipInfo.getPrice());
                userMemberShipInfo.setMobile(req.getMobile());
                userMemberShipInfo.setName(req.getName());
                // 待支付
                userMemberShipInfo.setStatus(0);
                String memberShipOrderNo = super.generateOrderNo("" + memberShipInfo.getMemberShipNo());
                userMemberShipInfo.setOrderNo(memberShipOrderNo);
                userMemberShipInfo.setParentOrderNo(pOrderNo);
                userMemberShipInfo.setCreatedTime(new Date());
                userMemberShipInfo.setUserId(req.getUserId());
                userMemberShipInfo.setMemberShipInfoId(memberShipInfo.getId());
                userMemberShipInfo.setTransactionId(pOrderNo);
                userMemberShipInfo.setAddress(req.getProvince() + req.getCity() + req.getAddress());
                userMemberShipInfo = mongoTemplate.insert(userMemberShipInfo);
                memberShipId = memberShipInfo.getId();
                log.info(":>>> 生成用户:{},会员卡订单:{}", req.getUserId(), JSON.toJSONString(userMemberShipInfo));
                // 生成会员卡订单
            } else {
                // 本身是会员
                remainNum = userPO.getRemainedNum() == null ? 0 : userPO.getRemainedNum();
            }
            for (CaInfo caInfo : caInfos) {
                UserCaInfo userCaInfo = new UserCaInfo();
                String caOrderNo = super.generateOrderNo("" + caInfo.getGoodsCode());
                userCaInfo.setOrderNo(caOrderNo);
                userCaInfo.setParentOrderNo(pOrderNo);
                userCaInfo.setTransactionId(pOrderNo);
                userCaInfo.setGoodsCode(caInfo.getGoodsCode());
                userCaInfo.setUserId(req.getUserId());
                userCaInfo.setCaInfo(caInfo);
                userCaInfo.setCaInfoId(caInfo.getId());
                // 待付款
                userCaInfo.setCaStatus(0);
                // 默认电子版证书
                userCaInfo.setMaterial(1);
                userCaInfo.setMobile(req.getMobile());
                userCaInfo.setName(req.getName());
                userCaInfo.setProvince(req.getProvince());
                userCaInfo.setCity(req.getCity());
                userCaInfo.setAddress(req.getAddress());
                userCaInfo.setArea(req.getArea());
                userCaInfo.setReceiveTime(date);
                userCaInfo.setUniversityId(req.getUniversityId());
                /**
                 * 类型,0:会员支付,1:现金支付,2:国青币支付
                 */
                // 生成证书订单
                // 会员卡抵扣
                if (remainNum == 0) {
                    userCaInfo.setPrice(caInfo.getPrice());
                    userCaInfo.setOriginalPrice(caInfo.getPrice());
                    userCaInfo.setPayDesc("现金支付");
                    userCaInfo.setPayFeeType("1");
                } else {
                    userCaInfo.setPrice(0);
                    userCaInfo.setOriginalPrice(caInfo.getPrice());
                    userCaInfo.setPayDesc("会员卡抵扣");
                    userCaInfo.setPayFeeType("0");
                    remainNum--;
                }
                userCaInfo.setActivityId(req.getActivityId());
                userCaInfo = mongoTemplate.insert(userCaInfo);
                log.info(":>>> 生成的证书订单:{}", JSON.toJSONString(userCaInfo));
            }
            log.info(":>>> 用户:{},提交订单生成的价格为:{}", req.getUserId(), cumputedPrice);

        } else {
            log.info(":>>> 用户没有选择的会员卡:{}", req.getUserId());
            for (CaInfo caInfo : caInfos) {
                // 生成证书订单
                UserCaInfo userCaInfo = new UserCaInfo();
                String caOrderNo = super.generateOrderNo("" + caInfo.getGoodsCode());
                userCaInfo.setOrderNo(caOrderNo);
                userCaInfo.setParentOrderNo(pOrderNo);
                userCaInfo.setTransactionId(pOrderNo);
                userCaInfo.setGoodsCode(caInfo.getGoodsCode());
                userCaInfo.setUserId(req.getUserId());
                userCaInfo.setCaInfo(caInfo);
                userCaInfo.setCaInfoId(caInfo.getId());
                // 待付款
                userCaInfo.setCaStatus(0);
                // 纸质证书
                userCaInfo.setMaterial(1);
                userCaInfo.setMobile(req.getMobile());
                userCaInfo.setName(req.getName());
                userCaInfo.setProvince(req.getProvince());
                userCaInfo.setCity(req.getCity());
                userCaInfo.setAddress(req.getAddress());
                userCaInfo.setArea(req.getArea());
                userCaInfo.setReceiveTime(date);
                userCaInfo.setUniversityId(req.getUniversityId());
                /**
                 * 类型,0:会员支付,1:现金支付,2:国青币支付
                 */
                // 生成证书订单
                userCaInfo.setPrice(caInfo.getPrice());
                userCaInfo.setOriginalPrice(caInfo.getPrice());
                userCaInfo.setPayDesc("现金支付");
                userCaInfo.setPayFeeType("1");
                userCaInfo.setActivityId(req.getActivityId());
                userCaInfo = mongoTemplate.insert(userCaInfo);
                log.info(":>>> 生成的证书订单:{}", JSON.toJSONString(userCaInfo));
            }
            log.info(":>>> 用户:{},提交订单生成的价格为:{}", req.getUserId(), cumputedPrice);
        }
        if (cumputedPrice.compareTo(0) == 1) {
            log.info(":>>> 用户:{} 订单现金支付", req.getUserId());
            OrderPO orderPO = new OrderPO();
            orderPO.setOrderNo(pOrderNo);
            orderPO.setSource(req.getSource());
            orderPO.setPayType(OrderPayTypeEnum.WX.getCode());
            GoodsInfo goods = new GoodsInfo();
            if (StringUtils.isNotBlank(pOrderNo)) {
                goods.setGoodsName(pOrderNo);
            } else {
                goods.setGoodsName("赞我商品");
            }
            log.info(":>>> 商品名字:{}", "赞我订单-" + pOrderNo);
            orderPO.setGoods(goods);
            orderPO.setPayPrice(req.getPrice());
            orderPO.setTotalPrice(req.getPrice());
            orderPO.setClientIp(req.getClientIp());
            orderPO.setTransactionId(pOrderNo);
            orderPO.setOpenId(userPO.getOpenId());
            orderPO.setPlatform(userPO.getCurrentPlatform());
            orderPO.setUserPO(req.getUserPO());
            orderPO.setNonceStr("" + date.getTime());
            orderPO.setTimestampStr("" + date.getTime() / 1000);
            Map<String, String> result = new HashMap<>();
            //获取预支付参数
            QResult<Map<String, String>> uniOrderResult = super.getUniOrderResult(orderPO);
            log.info(":>>> 获取微信预支付参数结果为:{}", JSON.toJSONString(uniOrderResult));
            // 支付成功
            if (uniOrderResult.code == 0) {
                result = uniOrderResult.data;
                log.info("placeOrder applyReq {} result {}", req, result);
            } else {
                log.info("placeOrder applyReq {} error msg {}", req, uniOrderResult.msg);
            }
            result.put("payFeeType", "1");
            result.put("payDesc", "微信支付");
            log.info(":>>> 微信支付参数为:{}", JSON.toJSONString(result));
            if ("wechat-h5".equals(orderPO.getPlatform())) {
                log.info(":>>> 平台是wechat-h5,设置JS SDK配置");
                WechatH5PayConfigDomain config = activityService.getPayConfig(userPO, req.getUrl(), orderPO.getNonceStr(), orderPO.getTimestampStr());
                result.put("appId", config.getAppId());
                result.put("signature", config.getSignature());
                result.put("nonceStr", config.getNonceStr());
                result.put("timeStamp", config.getTimestamp());
                result.put("jsApiList", JSON.toJSONString(config.getJsApiList()));
            }
            // TODO:更新订单状态:等待回调
            WechatPayCache cache = new WechatPayCache();
            cache.setOrderNo(pOrderNo);
            cache.setBizType("mix");
            cache.setType("parent");
            wechatPayCacheService.create(cache);

            Query queryReward = new Query().addCriteria(Criteria.where("activityId").is(req.getActivityId()).and("userId").is(req.getUserId()).and("rewardReceived").is(Boolean.TRUE));
            boolean exist = mongoTemplate.exists(queryReward, UserActivityReward.class);
            log.info(":>>> 用户:{},活动:{},领取状态为:{}", req.getUserId(), req.getActivityId(), exist);
            if (!exist) {
                UserActivityReward userActivityReward = new UserActivityReward();
                userActivityReward.setUserId(req.getUserId());
                userActivityReward.setActivityId(req.getActivityId());
                userActivityReward.setOrderNo(pOrderNo);
                userActivityReward.setRewardReceived(Boolean.FALSE);
                userActivityReward.setCreatedTime(new Date());
                mongoTemplate.insert(userActivityReward);
                log.info(":>>> 用户:{} 订单:{} 未领取,新增未领取记录", req.getUserId(), pOrderNo);
            }
            return result;
        } else {
            log.info(":>>> 用户:{} 订单会员卡购买次数抵扣", req.getUserId());
            // 会员卡抵扣
            HashMap<String, String> re = new HashMap<>();
            re.put("payFeeType", "0");
            re.put("price", "0");
            re.put("payDesc", String.format("已经开通会员，免费领取，还可领取%d次", remainNum));
            re.put("orderNo", pOrderNo);
            log.info(":>>> 会员支付参数为:{}", JSON.toJSONString(re));
            // TODO:更新订单状态:会员卡支付,进行扣减操作
            if (remainNum == 0) {
                userPO.setMemberShiped(false);
                userPO.setRemainedNum(remainNum);
                mongoTemplate.save(userPO);
            } else {
                userPO.setRemainedNum(remainNum);
                mongoTemplate.save(userPO);
            }
            Query query1 = new Query().addCriteria(Criteria.where("parentOderNo").is(pOrderNo));
            Update update = new Update();
            update.set("status", 1);
            mongoTemplate.updateFirst(query1, update, UserMemberShipInfo.class);
            Update updateUserCa = new Update();
            updateUserCa.set("caStatus", 1);
            mongoTemplate.updateMulti(query1, updateUserCa, UserCaInfo.class);
            return re;
        }
    }

    @Override
    public Map<String, String> payOrder(ActivityRewadDomain req, UserPO userPO) {
        String pOrderNo = req.getOrderNo();
        Query query = new Query().addCriteria(Criteria.where("orderNo").is(req.getOrderNo()));
        OrderInfo orderInfo = masterMongoTemplate.findOne(query, OrderInfo.class);
        Date date = new Date();
        if (Objects.nonNull(orderInfo.getCreatedTime())) {
            long orderTime = date.getTime() - orderInfo.getCreatedTime().getTime();
            if (orderTime > 24 * 60 * 60 * 1000) {
                log.info(":>>> 订单已超时,orderNo:{},createTime:{}", req.getOrderNo(), orderInfo.getCreatedTime());
                throw new BusinessException("订单已超时,请重新下单");
            }
        }
        log.info(":>>> 支付订单:{}", JSON.toJSONString(req));
        OrderPO orderPO = new OrderPO();
        orderPO.setOrderNo(pOrderNo);
        orderPO.setSource(req.getSource());
        orderPO.setPayType(OrderPayTypeEnum.WX.getCode());
        GoodsInfo goods = new GoodsInfo();
        if (StringUtils.isNotBlank(pOrderNo)) {
            goods.setGoodsName(pOrderNo);
        } else {
            goods.setGoodsName("赞我商品");
        }
        this.orderRedisTemplate.opsForValue().set(String.format(USER_ORDER_PAY, orderInfo.getOrderNo()), JSON.toJSONString(orderInfo), 30L, TimeUnit.MINUTES);
        PayConfigPage payConfig = activityPayConfigService.findByActivityId(orderInfo.getActivityId(), 0);
        Date currentDate = new Date();
        List<PayButtonConfigPage> payButtonConfigList = payConfig.getPayButtonConfigList();
        long count = payButtonConfigList.stream().filter(payButtonConfig -> PayButtonConfigPage.PAPER_CERTIFICATE.equals(payButtonConfig.getButtonType()) && payButtonConfig.getCaType().equals(orderInfo.getTaskBizType()) && currentDate.before(payButtonConfig.getEndTime())).count();
//        if (count == 0) {
//            log.error("用户->{}参与活动->{} 类型 {} 下单已超时", userPO.getId(), orderInfo.getActivityId(), req.getTaskBizType());
//            throw new BusinessException("领取已结束，无法提交订单");
//        }
//        checkUserOrder(userPO.getId(), orderInfo.getSignUpMobile(), orderInfo.getActivityId(),
//                orderInfo.getTaskBizType());
        orderPO.setGoods(goods);
        orderPO.setPayPrice(orderInfo.getTotalFee());
        orderPO.setTotalPrice(orderInfo.getTotalFee());
        orderPO.setClientIp(req.getClientIp());
        orderPO.setTransactionId(pOrderNo);
        orderPO.setOpenId(userPO.getOpenId());
        orderPO.setPlatform(userPO.getCurrentPlatform());
        orderPO.setUserPO(req.getUserPO());
        orderPO.setNonceStr("" + date.getTime());
        orderPO.setTimestampStr("" + date.getTime() / 1000);
        orderPO.setAppId(orderInfo.getAppId());
        orderPO.setMerchantId(orderInfo.getMechantId());
        Map<String, String> result = new HashMap<>();
        //获取预支付参数
        QResult<Map<String, String>> uniOrderResult = super.getUniOrderResult(orderPO);
        log.info(":>>> 获取微信预支付参数结果为:{}", JSON.toJSONString(uniOrderResult));
        // 支付成功
        if (uniOrderResult.code == 0) {
            result = uniOrderResult.data;
            log.info("placeOrder applyReq {} result {}", req, result);
        } else {
            log.error("placeOrder applyReq {} error msg {}", req, uniOrderResult.msg);
            throw new BusinessException(uniOrderResult.msg);
        }
        result.put("payFeeType", "1");
        result.put("payDesc", "微信支付");
        log.info(":>>> 微信支付参数为:{}", JSON.toJSONString(result));
        if ("wechat-h5".equals(orderPO.getPlatform())) {
            log.info(":>>> 平台是wechat-h5,设置JS SDK配置");
            WechatH5PayConfigDomain config = activityService.getPayConfig(userPO, req.getUrl(), orderPO.getNonceStr(), orderPO.getTimestampStr());
            result.put("appId", config.getAppId());
            result.put("signature", config.getSignature());
            result.put("nonceStr", config.getNonceStr());
            result.put("timeStamp", config.getTimestamp());
            result.put("jsApiList", JSON.toJSONString(config.getJsApiList()));
        }

        Query queryCache = new Query().addCriteria(Criteria.where("orderNo").is(pOrderNo));
        boolean existC = masterMongoTemplate.exists(queryCache, WechatPayCache.class);
        if (!existC) {
            WechatPayCache cache = new WechatPayCache();
            cache.setOrderNo(pOrderNo);
            cache.setBizType("mix");
            cache.setType("parent");
            wechatPayCacheService.create(cache);
        }
        Query queryReward = new Query().addCriteria(Criteria.where("activityId").is(req.getActivityId()).and("userId").is(req.getUserId()).and("rewardReceived").is(Boolean.TRUE));
        boolean exist = mongoTemplate.exists(queryReward, UserActivityReward.class);
        log.info(":>>> 用户:{},活动:{},领取状态为:{}", req.getUserId(), req.getActivityId(), exist);
        if (!exist) {
            UserActivityReward userActivityReward = new UserActivityReward();
            userActivityReward.setUserId(req.getUserId());
            userActivityReward.setActivityId(req.getActivityId());
            userActivityReward.setOrderNo(pOrderNo);
            userActivityReward.setRewardReceived(Boolean.FALSE);
            userActivityReward.setCreatedTime(new Date());
            mongoTemplate.insert(userActivityReward);
            log.info(":>>> 用户:{} 订单:{} 未领取,新增未领取记录", req.getUserId(), pOrderNo);
        }
        return result;
    }

    @Override
    public MyCaInfoDTO queryMyCaInfo(MyCaInfoVO myCaInfoVO) {
        String userName = myCaInfoVO.getUserName();
        String certificateNo = myCaInfoVO.getCertificateNo();
        log.info("【证书查询】 用户 ->{},证书编号 ->{}", userName, certificateNo);
        Query query = new Query();
        query.addCriteria(Criteria.where("certificateNo").is(certificateNo));
        query.addCriteria(Criteria.where("userName").is(userName));
//        query.with(new Sort(Sort.Direction.DESC, "createdTime"));
        Sort sort = Sort.by(Sort.Direction.DESC, "createdTime");
        query.with(sort);
        UserCaRecord userCaInfo = this.mongoTemplate.findOne(query, UserCaRecord.class);
        if (Objects.isNull(userCaInfo)) {
            throw new BusinessException("亲,未查询到您拥有该证书,请联系我们客服人员确认");
        }
        MyCaInfoDTO myCaInfo = new MyCaInfoDTO();
        myCaInfo.setUserName(userName);
        myCaInfo.setCertificateNo(certificateNo);
        myCaInfo.setCaName(userCaInfo.getCaName());
        myCaInfo.setLevelName(userCaInfo.getLevelName());
        myCaInfo.setReceiveTime(userCaInfo.getCaTime());
        myCaInfo.setUniversityName(userCaInfo.getUniversityName());
        myCaInfo.setCaOrg(userCaInfo.getCaOrg());
        return myCaInfo;
    }

    @Override
    public boolean payCallBack(String userId, String orderNo) {
        log.info(":>>> 支付回调用户:{},{}", userId, orderNo);
        Query query = new Query().addCriteria(Criteria.where("userId").is(userId).and("orderNo").is(orderNo));
        Update update = new Update();
        update.set("caStatus", "1");
        update.set("updatedTime", new Date());
        UpdateResult result = mongoTemplate.updateFirst(query, update, UserCaInfo.class);
        log.info(":>>> 支付回调:{}", result.getModifiedCount() > 0 ? true : false);
        return true;
    }


    @Override
    public Map<String, String> placeOrder(PlaceOrderReq req) {
        return null;
    }

    @Override
    public boolean handlePayNotify(OrderPO orderPO) {
        return false;
    }

    @Override
    public OrderInfo placeOrder(PlaceOrderVO req, UserPO userPO) {
        log.info("placeOrder 开始处理用户下单接口 req:{},userPO:{}", JSON.toJSONString(req), JSON.toJSONString(userPO));
        if (StringUtils.isAnyBlank(req.getActivityId(), req.getTaskBizType()) || CollectionUtils.isEmpty(req.getCaIds())) {
            log.error("placeOrder 请求参数异常");
            throw new BusinessException("用户下单参数错误");
        }
        String orderNo = super.generateOrderNo("证书");
        log.info("placeOrder 生成的证书订单编号:{}", orderNo);
        if (super.resubmit(3L, RequestContext.getUserId(), orderNo)) {
            log.error("placeOrder 有已经待支付的订单,请不要重复支付");
            throw new BusinessException("请勿重复发起支付~");
        }
        ActivityInfo activityInfo = cacheActivityService.findById(req.getActivityId());
        Date date = new Date();
        WechatConfigInfo wechatConfigInfo = wechatConfigInfoService.find(userPO.getAppId());
        if (Objects.isNull(wechatConfigInfo) || CollectionUtils.isEmpty(wechatConfigInfo.getMerchantIds())) {
            log.error(":>>> 微信公众号配置错误:{}", userPO.getAppId());
            throw new BusinessException("当前支付人数多,稍后重试");
        }
        PayConfigPage payConfig = activityPayConfigService.findByActivityId(req.getActivityId(), 0);
        PostageTemplate postageTemplate = null;
        if (Objects.nonNull(payConfig) && StringUtils.isNotBlank(payConfig.getPostageTemplateId())) {
            postageTemplate = postageTemplateService.findOne(payConfig.getPostageTemplateId());
        }
        log.info(":>>> 活动:{} 邮费模版:{}", req.getActivityId(), JSON.toJSON(postageTemplate));
        OrderInfo orderInfo = new OrderInfo();
        try {
            ActivityUserRecord activityUserRecord = platformOtherActivityService.findByOpenidOrMoble(req.getActivityId(), userPO.getOpenId(), req.getMobile(), req.getTaskBizType());

            orderInfo.setCaPrintName(activityUserRecord.getName());
            orderInfo.setSignUpMobile(activityUserRecord.getMobile());
            orderInfo.setSignUpName(activityUserRecord.getName());
            if (StringUtils.isNotBlank(activityUserRecord.getRecieveMobile())) {
                orderInfo.setMobile(activityUserRecord.getRecieveMobile());
            } else {
                orderInfo.setMobile(activityUserRecord.getMobile());
            }
            orderInfo.setName(activityUserRecord.getRecieveName());
            orderInfo.setProvince(activityUserRecord.getProvince());
            orderInfo.setCity(activityUserRecord.getCity());
            orderInfo.setArea(activityUserRecord.getArea());
            orderInfo.setAddress(activityUserRecord.getAddress());
            if (StringUtils.isAnyBlank(orderInfo.getMobile(), orderInfo.getName(), orderInfo.getProvince(), orderInfo.getArea(), orderInfo.getCity(), orderInfo.getAddress())) {
                UserInfoExtend cacheUser = userInfoExtendService.findCacheUserByUserId(userPO);
                if (Objects.nonNull(cacheUser) && cacheUser.checkUserAdress()) {
                    String receiveName = cacheUser.getReceiveName();
                    String receiveMobile = cacheUser.getReceiveMobile();
                    String address = cacheUser.getAddress();
                    if (!StringUtils.isAllBlank(receiveName, receiveMobile, address)) {
                        orderInfo.setProvince(cacheUser.getProvince());
                        orderInfo.setCity(cacheUser.getCity());
                        orderInfo.setAddress(address);
                        orderInfo.setArea(cacheUser.getArea());
                        orderInfo.setMobile(receiveMobile);
                        orderInfo.setName(receiveName);
                    }
                }
            }
            orderInfo.setTaskBizType(req.getTaskBizType());
            orderInfo.setUniversityId(activityUserRecord.getUniversityId());
            orderInfo.setUniversityName(activityUserRecord.getUniversityName());
        } catch (Exception e) {
            throw new BusinessException("用户未报名活动");
        }
        if (StringUtils.isAnyBlank(orderInfo.getMobile(), orderInfo.getName(), orderInfo.getProvince(), orderInfo.getArea(), orderInfo.getCity(), orderInfo.getAddress())) {
            log.error("【下单错误-收货提示】收货地址为空 activityId->{}|userId->{}|provice->{}|area->{}|address->{}", activityInfo.getId(), userPO.getId(), orderInfo.getProvince(), orderInfo.getArea(), orderInfo.getAddress());
            throw new BusinessException("请1分钟后重试，服务繁忙！");
        }

        Date currentDate = new Date();
        List<PayButtonConfigPage> payButtonConfigList = payConfig.getPayButtonConfigList();
        long count = payButtonConfigList.stream().filter(payButtonConfig -> PayButtonConfigPage.PAPER_CERTIFICATE.equals(payButtonConfig.getButtonType()) && payButtonConfig.getCaType().equals(req.getTaskBizType()) && currentDate.before(payButtonConfig.getEndTime())).count();
        if (count == 0) {
            log.error("用户->{}参与活动->{} 类型 {} 下单已超时", userPO.getId(), activityInfo.getName(), req.getTaskBizType());
            throw new BusinessException("领取已结束，无法提交订单");
        }
        checkUserOrder(userPO.getId(), orderInfo.getSignUpMobile(), activityInfo.getId(), orderInfo.getTaskBizType());
        if (StringUtils.isNotBlank(orderInfo.getUniversityId())) {
            Query queryU = new Query().addCriteria(Criteria.where("id").is(orderInfo.getUniversityId()));
            UniversityInfo universityInfo = mongoTemplate.findOne(queryU, UniversityInfo.class);
            if (Objects.nonNull(universityInfo)) {
                orderInfo.setUniversityName(universityInfo.getName());
            }
        }
        orderInfo.setOrderNo(orderNo);
        orderInfo.setCreatedTime(date);
        orderInfo.setStatus("0");
        orderInfo.setActivityId(req.getActivityId());
        if ("607bc49aff34157f911a3471".equals(req.getActivityId())) {
            if (!"wxbaba4b2c54e8881a".equals(userPO.getAppId())) {
                userPO.setAppId("wxbaba4b2c54e8881a");
                log.info(":>>> 活动:607bc49aff34157f911a3471 appId 不一致");
            }
        }
        orderInfo.setAppId(userPO.getAppId());
        orderInfo.setOpenId(userPO.getOpenId());
        orderInfo.setPlatform("wechat-h5");
        PlatformConfig platformConfig = platformConfigService.find();
        Integer price = 0;
        Integer num = 0;
        Integer totalPrice = 0;
        Integer expressFee = 0;
        Integer discountPrice = 0;
        String expressTips = "";
        //初始化是否包含有礼品订单
        List<ItemInfoReq> itemList = req.getItemList();
        List<Integer> giftList = Lists.newArrayListWithCapacity(req.getCaIds().size());
        if (CollectionUtils.isEmpty(itemList)) {
            throw new BusinessException("对不起，未选择任何商品不能参与购买");
        }
        UserActivityDeductionVo vo = userActivityDeductionService.getUserDeductionVo(payConfig, userPO.getId(), orderInfo.getTaskBizType());
        boolean deductionExpire = vo.getHasDeduction() && vo.getDiffTime() > 0;
        for (ItemInfoReq item : itemList) {
            CaInfo caInfo = cacheCaInfoService.findById(item.getItemId());
            if (Objects.isNull(caInfo)) {
                log.error(":>>> 证书不存在:{}", item.getItemId());
                throw new BusinessException("证书不存在");
            }

            String oorderNo = super.generateOrderNo("证书子订单");
            OOrderInfo oOrderInfo = buildOOrderInfo(caInfo, userPO, req.getActivityId(), orderNo, oorderNo, false, item.getNum());
            discountPrice = discountPrice + (caInfo.getOriginalPrice() == null ? caInfo.getPrice() : caInfo.getOriginalPrice() - caInfo.getPrice());
            orderInfo.setTitle(caInfo.getName());
            if (ArrayUtils.isEmpty(caInfo.getCertificateImages())) {
                orderInfo.setImageUrl(caInfo.getCertificateImage());
            } else {
                orderInfo.setImageUrl(caInfo.getCertificateImages()[0]);
            }
            // 获取到证书-即证书
            if (!oOrderInfo.getCaGift()) {
                giftList.add(1);
            }
            orderInfo.setGift(caInfo.getGift());
            price = price + Math.multiplyExact(caInfo.getPrice(), item.getNum());
            //大于1分才退款 偏于地区才收取邮费，真的
            Integer e = 0;
            Integer extraFee = 0;
            if (caInfo.getPrice() > 1) {
                HashMap<String, Integer> ee = getOrderExpreeFee(postageTemplate, orderInfo.getProvince(), caInfo.getExpressFee());
                log.info(":>>> 邮费项:{}", JSON.toJSONString(ee));
                e = ee.get("fee");
                extraFee = ee.get("extraFee");
                orderInfo.setExtraExpressFee(extraFee);
            }
            totalPrice = totalPrice + Math.multiplyExact(caInfo.getPrice(), item.getNum()) + e + extraFee;
            expressFee = expressFee + e;
            num += item.getNum();
            orderInfoTipService.setOOrderTips(orderInfo, platformConfig, oOrderInfo);
            mongoTemplate.insert(oOrderInfo);
            log.info(":>>> 证书:{} 邮费提示语:{}", caInfo.getId(), caInfo.getExpressFeeTips());
            if (StringUtils.isNotBlank(caInfo.getExpressFeeTips())) {
                expressTips = caInfo.getExpressFeeTips();
            }
            if (Objects.nonNull(caInfo.getGiftItems()) && !CollectionUtils.isEmpty(caInfo.getGiftItems())) {
                for (GiftCaInfo c : caInfo.getGiftItems()) {
                    CaInfo giftCaInfo = this.mongoTemplate.findById(c.getId(), CaInfo.class);
                    if (Objects.nonNull(giftCaInfo)) {
                        String ooorderNo = super.generateOrderNo("证书子订单");
                        OOrderInfo ooOrderInfo = buildOOrderInfo(giftCaInfo, userPO, req.getActivityId(), orderNo, ooorderNo, true, 1);
                        ooOrderInfo.setShow(c.getShow());
                        mongoTemplate.insert(ooOrderInfo);
                    }

                }
            }
        }
        long caCount = giftList.stream().filter(gift -> gift == 1).count();
        log.info("【订单包含证书数量】orderNo - > {} count - > {}", orderNo, caCount);
        if (caCount == 0) {
            orderInfo.setCategory("gift");
        }
        if (deductionExpire) {
            int diff = totalPrice - vo.getMoney();
            if (diff >= 1) {
                totalPrice = diff;
                orderInfo.setDeductionFee(vo.getMoney());
                orderInfo.setDeductionEndDate(vo.getEndTime());
            }
        }
        orderInfo.setTotalFee(totalPrice);
        orderInfo.setItemPrice(price);
        orderInfo.setNum(num);
        orderInfo.setExpressFee(expressFee);
        orderInfo.setDiscountFee(discountPrice);
        orderInfo.setAccountInfoId(userPO.getId());
        orderInfo.setTips(activityInfo.getOrderTips());
        orderInfo.setSmsActivityName(activityInfo.getSmsActivityName());
        orderInfo.setPaymentSmsEnabled(activityInfo.getPaymentSmsEnabled());
        orderInfo.setCreatedTime(new Date());
        orderInfo.setExpressDesc(postageTemplate.getExpressDesc());
        if (StringUtils.isNotBlank(expressTips)) {
            orderInfo.setExpressFeeTips(expressTips);
        } else {
            orderInfo.setExpressFeeTips(postageTemplate.getExpressFeeTips());
        }
        // 随机
        String merchantId = wechatConfigInfo.getMerchantIds().get(random(wechatConfigInfo.getMerchantIds().size()));
        WechatMerchantConfig merchant = wechatMerchantConfigService.findByMerchantIdAndDecrypt(merchantId);
        if (Objects.isNull(merchant)) {
            log.error(":>>> 微信配置错误:{} ,商户号不存在,请联系管理员", merchantId);
            throw new BusinessException("微信支付异常,请联系在线客服");
        }
        orderInfo.setMechantId(merchant.getMerchantId());
        orderInfo.setMechantName(merchant.getMerchantName());
        orderInfo = mongoTemplate.insert(orderInfo);
        log.info(":>>> 订单:{},邮费提示语:{},证书配置提示语:{}", orderInfo.getOrderNo(), orderInfo.getExpressFeeTips(), expressTips);
        return orderInfo;
    }

    @Override
    public OrderInfo placeOrderV2(PlaceOrderV2VO req, UserPO userPO) {
        log.info(":>>> 开始处理用户下单V2接口:{},用户:{}", JSON.toJSONString(req), JSON.toJSONString(userPO));
        if (Objects.isNull(req) || StringUtils.isBlank(req.getActivityId()) || CollectionUtils.isEmpty(req.getItems())) {
            log.error(":>>> 用户下单参数错误:活动、商品为空");
            throw new BusinessException("用户下单参数错误");
        }
        UserInfoExtend extend = new UserInfoExtend();
        extend.setProvince(req.getProvince());
        extend.setCity(req.getCity());
        extend.setArea(req.getArea());
        extend.setAddress(req.getAddress());
        extend.setUserId(userPO.getId());
        userInfoExtendService.updateAddressInfoByUserId(extend, userPO.getId());
        String orderNo = super.generateOrderNo("证书");
        log.info(":>>> 生成的证书订单编号:{}", orderNo);
        if (super.resubmit(3L, RequestContext.getUserId(), orderNo)) {
            log.info(":>>> 有已经待支付的订单,请不要重复支付");
            throw new BusinessException("请勿重复发起支付~");
        }
        ActivityInfo activityInfo = cacheActivityService.findById(req.getActivityId());
        Date date = new Date();
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setVersion("v2");
        WechatConfigInfo wechatConfigInfo = wechatConfigInfoService.find(userPO.getAppId());
        if (Objects.isNull(wechatConfigInfo) || Objects.isNull(wechatConfigInfo.getMerchantIds()) || CollectionUtils.isEmpty(wechatConfigInfo.getMerchantIds())) {
            log.error(":>>> 微信公众号配置错误:{}", userPO.getAppId());
           /* WechatPayAlarm alarm = new WechatPayAlarm();
            alarm.setAppId(userPO.getAppId());
            alarm.setComment("当前支付人数多,稍后重试");
            alarm.setType("config");
            mongoTemplate.insert(alarm);*/
            throw new BusinessException("当前支付人数多,稍后重试1");
        }
        PayConfigPage payConfig = activityPayConfigService.findByActivityId(req.getActivityId(), 0);
        PostageTemplate postageTemplate = null;
        if (Objects.nonNull(payConfig) && StringUtils.isNotBlank(payConfig.getPostageTemplateId())) {
            postageTemplate = postageTemplateService.findOne(payConfig.getPostageTemplateId());

        }
        log.info(":>>> 活动:{} 邮费模版:{}", req.getActivityId(), JSON.toJSON(postageTemplate));
        try {
            orderInfo.setCaPrintName(req.getCaPrintName());
            orderInfo.setSignUpMobile(req.getMobile());
            orderInfo.setSignUpName(req.getName());
            orderInfo.setMobile(req.getMobile());
            orderInfo.setName(req.getName());
            orderInfo.setProvince(req.getProvince());
            orderInfo.setCity(req.getCity());
            orderInfo.setArea(req.getArea());
            orderInfo.setAddress(req.getAddress());
            if (StringUtils.isAnyBlank(orderInfo.getMobile(), orderInfo.getName(), orderInfo.getProvince(), orderInfo.getArea(), orderInfo.getCity(), orderInfo.getAddress())) {
                UserInfoExtend cacheUser = userInfoExtendService.findCacheUserByUserId(userPO);
                if (Objects.nonNull(cacheUser) && cacheUser.checkUserAdress()) {
                    String receiveName = cacheUser.getReceiveName();
                    String receiveMobile = cacheUser.getReceiveMobile();
                    String address = cacheUser.getAddress();
                    if (!StringUtils.isAllBlank(receiveName, receiveMobile, address)) {
                        orderInfo.setProvince(cacheUser.getProvince());
                        orderInfo.setCity(cacheUser.getCity());
                        orderInfo.setAddress(address);
                        orderInfo.setArea(cacheUser.getArea());
                        orderInfo.setMobile(receiveMobile);
                        orderInfo.setName(receiveName);
                    }
                }
            }
            // TODO: 需要检查
//            orderInfo.setTaskBizType(req.getTaskBizType());
            orderInfo.setUniversityId(req.getUniversityId());
            orderInfo.setUniversityName(req.getUniversityName());
        } catch (Exception e) {
            throw new BusinessException("用户未报名活动");
        }
        if (StringUtils.isAnyBlank(orderInfo.getMobile(), orderInfo.getName(), orderInfo.getProvince(), orderInfo.getArea(), orderInfo.getCity(), orderInfo.getAddress())) {
            log.error("【下单错误-收货提示】收货地址为空 activityId->{}|userId->{}|provice->{}|area->{}|address->{}", activityInfo.getId(), userPO.getId(), orderInfo.getProvince(), orderInfo.getArea(), orderInfo.getAddress());
            throw new BusinessException("请1分钟后重试，服务繁忙！");
        }
//        checkUserOrder(userPO.getId(), orderInfo.getSignUpMobile(), activityInfo.getId(), orderInfo.getTaskBizType());
        if (StringUtils.isNotBlank(orderInfo.getUniversityId()) && StringUtils.isBlank(orderInfo.getUniversityName())) {
            UniversityInfo universityInfo = universityInfoService.findOne(orderInfo.getUniversityId());
            if (Objects.nonNull(universityInfo)) {
                orderInfo.setUniversityName(universityInfo.getName());
            }
        }
        orderInfo.setOrderNo(orderNo);
        orderInfo.setCreatedTime(date);
        orderInfo.setStatus("0");
        orderInfo.setActivityId(req.getActivityId());
        if ("607bc49aff34157f911a3471".equals(req.getActivityId())) {
            if (!"wxbaba4b2c54e8881a".equals(userPO.getAppId())) {
                userPO.setAppId("wxbaba4b2c54e8881a");
                log.info(":>>> 活动:607bc49aff34157f911a3471 appId 不一致");
            }
        }
        orderInfo.setAppId(userPO.getAppId());
        orderInfo.setOpenId(userPO.getOpenId());
        orderInfo.setPlatform("wechat-h5");
        PlatformConfig platformConfig = platformConfigService.find();
        Integer price = 0;
        Integer num = 0;
        Integer expressFee = 0;
        String expressTips = "";
        Integer caNum = 0;
        for (ItemInfoReq item : req.getItems()) {
            CaInfo caInfo = cacheCaInfoService.findById(item.getItemId());
            if (Objects.isNull(caInfo)) {
                log.error(":>>> 证书不存在:{}", item.getItemId());
                throw new BusinessException("证书不存在");
            }
            if (caInfo.getItemType() != 2) {
                caNum++;
            }
            String taskBizType = userPurchaseCaService.getItemTaskBizType(caInfo);
            log.info(":>>> 商品的taskBizType是:{},{}", caInfo.getId(), taskBizType);
            String oorderNo = super.generateOrderNo("证书子订单");
            OOrderInfo oOrderInfo = buildOOrderInfo(caInfo, userPO, req.getActivityId(), orderNo, oorderNo, false, item.getNum());
            orderInfo.setTitle(caInfo.getName());
            orderInfo.setTaskBizType(taskBizType);
            oOrderInfo.setTaskBizType(taskBizType);
            if (ArrayUtils.isEmpty(caInfo.getCertificateImages())) {
                orderInfo.setImageUrl(caInfo.getCertificateImage());
            } else {
                orderInfo.setImageUrl(caInfo.getCertificateImages()[0]);
            }
            // 获取到证书-即证书
            if (!oOrderInfo.getCaGift()) {
                // TODO:需要处理
//                giftList.add(1);
            }
            orderInfo.setGift(caInfo.getGift());
            price = price + Math.multiplyExact(caInfo.getPrice(), item.getNum());
            //大于1分才退款 偏于地区才收取邮费，真的
            Integer e = 0;
            Integer extraFee = 0;
            if (caInfo.getPrice() > 1) {
                HashMap<String, Integer> ee = getOrderExpreeFee(postageTemplate, orderInfo.getProvince(), caInfo.getExpressFee());
                log.info(":>>> 邮费项:{}", JSON.toJSONString(ee));
                e = ee.get("fee");
                extraFee = ee.get("extraFee");
                orderInfo.setExtraExpressFee(extraFee);
            }
            expressFee = expressFee + e;
            num += item.getNum();
            orderInfoTipService.setOOrderTips(orderInfo, platformConfig, oOrderInfo);
            oOrderInfo.setTaskBizType(taskBizType);
            mongoTemplate.insert(oOrderInfo);
            log.info(":>>> 证书:{} 邮费提示语:{}", caInfo.getId(), caInfo.getExpressFeeTips());
            if (StringUtils.isNotBlank(caInfo.getExpressFeeTips())) {
                expressTips = caInfo.getExpressFeeTips();
            }
            if (Objects.nonNull(caInfo.getGiftItems()) && !CollectionUtils.isEmpty(caInfo.getGiftItems())) {
                for (GiftCaInfo c : caInfo.getGiftItems()) {
                    CaInfo giftCaInfo = this.mongoTemplate.findById(c.getId(), CaInfo.class);
                    if (Objects.nonNull(giftCaInfo)) {
                        String ooorderNo = super.generateOrderNo("证书子订单");
                        OOrderInfo ooOrderInfo = buildOOrderInfo(giftCaInfo, userPO, req.getActivityId(), orderNo, ooorderNo, true, 1);
                        ooOrderInfo.setTaskBizType(taskBizType);
                        mongoTemplate.insert(ooOrderInfo);
                    }

                }
            }
        }
        log.info("【订单包含证书数量】orderNo - > {} count - > {}", orderNo, caNum);
        if (caNum == 0) {
            orderInfo.setCategory("gift");
        }
        OrderConfirmComputePriceReq computePriceReq = new OrderConfirmComputePriceReq();
        computePriceReq.setUserId(req.getUserId());
        computePriceReq.setActivityId(req.getActivityId());
        computePriceReq.setProvince(req.getProvince());
        computePriceReq.setCity(req.getCity());
        for (ItemInfoReq itemInfoReq : req.getItems()) {
            CaInfo cc = new CaInfo();
            cc.setId(itemInfoReq.getItemId());
            cc.setNum(itemInfoReq.getNum());
            computePriceReq.getItems().add(cc);
        }
        OrderConfirmComputePriceRes priceRes = payV2Service.computPrice(computePriceReq);
        if (Objects.nonNull(priceRes)) {
            orderInfo.setDiscountFee(priceRes.getDiscountFee());
            orderInfo.setTotalFee(priceRes.getTotalFee());
            orderInfo.setOriginalTotalFee(priceRes.getOriginalTotalFee());
            orderInfo.setCouponDiscountFee(priceRes.getCouponDiscountFee());
            orderInfo.setSubsidyOfDoubleCa(priceRes.getSubsidyOfDoubleCa());
            orderInfo.setNum(num);
            orderInfo.setCouponNum(priceRes.getCouponNum());
        }
        orderInfo.setItemPrice(price);
        orderInfo.setExpressFee(expressFee);
        orderInfo.setAccountInfoId(userPO.getId());
        orderInfo.setTips(activityInfo.getOrderTips());
        orderInfo.setCreatedTime(new Date());
        orderInfo.setExpressDesc(postageTemplate.getExpressDesc());
        if (StringUtils.isNotBlank(expressTips)) {
            orderInfo.setExpressFeeTips(expressTips);
        } else {
            orderInfo.setExpressFeeTips(postageTemplate.getExpressFeeTips());
        }
        // 随机
        String merchantId = wechatConfigInfo.getMerchantIds().get(random(wechatConfigInfo.getMerchantIds().size()));
        WechatMerchantConfig merchant = wechatMerchantConfigService.findByMerchantIdAndDecrypt(merchantId);
        if (Objects.isNull(merchant)) {
            log.error(":>>> 微信配置错误:{} ,商户号不存在,请联系管理员", merchantId);
            throw new BusinessException("微信支付异常,请联系在线客服");
        }
        orderInfo.setMechantId(merchant.getMerchantId());
        orderInfo.setMechantName(merchant.getMerchantName());
        orderInfo = mongoTemplate.insert(orderInfo);
        log.info(":>>> 订单:{},邮费提示语:{},证书配置提示语:{}", orderInfo.getOrderNo(), orderInfo.getExpressFeeTips(), expressTips);
        return orderInfo;
    }

    @Override
    public VipRedeemCodeVo getRedeemCode(String subOrderNo, String userId, boolean isMobileLogin) {
        return tsCardService.getRedeemCode(subOrderNo, userId, isMobileLogin);
    }

    private Integer random(int max) {
        if (max == 0) {
            return 0;
        }
        return ThreadLocalRandom.current().nextInt(max);
    }

    private void checkUserOrder(String userId, String signUpMobile, String activityId, String taskBizType) {
        Query query = new Query();
        query.addCriteria(Criteria.where("accountInfoId").is(userId));
        query.addCriteria(Criteria.where("activityId").is(activityId));
        query.addCriteria(Criteria.where("taskBizType").is(taskBizType));
        query.addCriteria(Criteria.where("status").in(Arrays.asList("1", "2", "3", "4", "5")));
        boolean exists = this.masterMongoTemplate.exists(query, OrderInfo.class);
        if (exists) {
            log.error("用户->{} 重复购买活动 ->{} 类型 - >{}", userId, activityId, taskBizType);
            throw new BusinessException("您已领取此证书/礼品，请勿重复领取");
        }
        if (StringUtils.isBlank(signUpMobile)) {
            return;
        }
        query = new Query();
        query.addCriteria(Criteria.where("signUpMobile").is(signUpMobile));
        query.addCriteria(Criteria.where("activityId").is(activityId));
        query.addCriteria(Criteria.where("taskBizType").is(taskBizType));
        query.addCriteria(Criteria.where("status").in(Arrays.asList("1", "2", "3", "4", "5")));
        boolean exists2 = this.masterMongoTemplate.exists(query, OrderInfo.class);
        if (exists2) {
            log.error("手机号验证 用户->{} 重复购买活动 ->{} 类型 - >{}", userId, activityId, taskBizType);
            throw new BusinessException("您已领取此证书/礼品，请勿重复领取");
        }

    }

    @Override
    public OrderInfo getOrderDetail(String orderNo, String userId, String platForm) {
        log.info(":>>> 开始获取证书订单:{},{}", orderNo, userId);
        if (StringUtils.isBlank(orderNo) || StringUtils.isBlank(userId)) {
            log.error(":>>> 查询证书订单参数错误:订单编号和用户ID为空");
            throw new BusinessException("查询证书订单参数错误:订单编号和用户ID为空");
        }
        OrderInfo orderInfo = cacheOrderService.getByOrderNoAndUserId(orderNo, userId, platForm);
        //orderInfo.setPostController(checkOrderPostController(orderNo, orderInfo.getStatus(), orderInfo.getPayTime()));
        return orderInfo;
    }

    @Override
    public String getOrderStatus(String orderNo) {
        String orderNoKey = String.format(USER_ORDER_PAY, orderNo);
        String orderByCacheOrderNo = this.orderRedisTemplate.opsForValue().get(orderNoKey);
        if (StringUtils.isNotBlank(orderByCacheOrderNo)) {
            OrderInfo orderInfo = JSON.parseObject(orderByCacheOrderNo, OrderInfo.class);
            return orderInfo.getStatus();
        }
        Query query = new Query().addCriteria(Criteria.where("orderNo").is(orderNo));
        OrderInfo orderInfo = this.masterMongoTemplate.findOne(query, OrderInfo.class);
        if (Objects.isNull(orderInfo)) {
            log.error(":>>> 订单数据不存在:{}", orderNo);
            throw new BusinessException("订单数据不存在");
        }
        return orderInfo.getStatus();
    }

    @Override
    public Page<OrderInfo> getOrderInfos(OrderInfoQueryVO req) {
        log.info(":>>> 开始获取用户订单列表:{}", JSON.toJSONString(req));
        if (Objects.isNull(req)) {
            req = new OrderInfoQueryVO();
            req.setPage(1);
            req.setPageSize(50);

        }
        UserPO currentUser = req.getUserPO();
        Query query = new Query();
        if (StringUtils.isNotBlank(req.getUserId())) {
            List<String> mobiles = visitorUserService.findSameMobiles(req.getUserId());
            if (StringUtils.isNotBlank(req.getMobileStr()) && !mobiles.contains(req.getMobileStr())) {
                mobiles.add(req.getMobileStr());
            }
            log.info(":>>> 用户:{},相同手机号:{}", req.getUserId(), JSON.toJSON(mobiles));
            if (!CollectionUtils.isEmpty(mobiles)) {
                Criteria criteria = new Criteria();
                switch (req.getPlatform()) {
                    case "qq": {
                        criteria.orOperator(Criteria.where("accountInfoId").is(req.getUserId()), Criteria.where("mobile").in(mobiles));
                        query.addCriteria(criteria);
                        query.addCriteria(Criteria.where("platform").is(req.getPlatform()));
                        query.addCriteria(Criteria.where("appId").is(req.getAppId()));
                        break;
                    }
                    case "wechat-h5": {
                        query.addCriteria(Criteria.where("platform").is(req.getPlatform()));
                        criteria.orOperator(Criteria.where("accountInfoId").is(req.getUserId()), Criteria.where("mobile").in(mobiles));
                        query.addCriteria(criteria);
                        break;
                    }
                    case "h5": {
                        query.addCriteria(Criteria.where("platform").is("wechat-h5"));
                        criteria.orOperator(Criteria.where("accountInfoId").is(req.getUserId()), Criteria.where("mobile").in(mobiles));
                        query.addCriteria(criteria);
                        break;
                    }
                    case "wechat-mini": {
                        if (!CollectionUtils.isEmpty(currentUser.getMobileSet())) {
                            mobiles.addAll(currentUser.getMobileSet());
                        } else {
                            query.addCriteria(Criteria.where("platform").is(req.getPlatform()));
                        }
                        criteria.orOperator(Criteria.where("accountInfoId").is(req.getUserId()), Criteria.where("mobile").in(mobiles));
                        query.addCriteria(criteria);
                        break;
                    }
                    default:
                        break;
                }
            } else {

                switch (req.getPlatform()) {
                    case "qq":
                        query.addCriteria(Criteria.where("accountInfoId").is(req.getUserId()));
                        query.addCriteria(Criteria.where("platform").is(req.getPlatform()));
                        query.addCriteria(Criteria.where("appId").is(req.getAppId()));
                        break;
                    case "wechat-h5":
                        query.addCriteria(Criteria.where("accountInfoId").is(req.getUserId()));
                        query.addCriteria(Criteria.where("platform").is(req.getPlatform()));
                        break;
                    case "h5":
                        query.addCriteria(Criteria.where("accountInfoId").is(req.getUserId()));
                        query.addCriteria(Criteria.where("platform").is("wechat-h5"));
                        break;
                    case "wechat-mini":
                        if (!CollectionUtils.isEmpty(currentUser.getMobileSet())) {
                            Criteria criteria = new Criteria();
                            criteria.orOperator(Criteria.where("accountInfoId").is(req.getUserId()), Criteria.where("mobile").in(currentUser.getMobileSet()));
                            query.addCriteria(criteria);
                        } else {
                            query.addCriteria(Criteria.where("accountInfoId").is(req.getUserId()));
                            query.addCriteria(Criteria.where("platform").is(req.getPlatform()));
                        }
                        break;
                    default:
                        break;
                }
            }
        }

        List<String> statuses = new ArrayList<>();
        if (Objects.nonNull(req.getStatuses())) {
            for (String s : req.getStatuses()) {
                if (StringUtils.isNotBlank(s) && !statuses.contains(s)) {
                    statuses.add(s);
                }
            }
        }
        req.setStatuses(statuses);
        // 过滤待付款订单
        if (!CollectionUtils.isEmpty(req.getStatuses())) {
            query.addCriteria(Criteria.where("status").in(req.getStatuses()));
            //
            if (req.getStatuses().size() == 1) {
                String status = req.getStatuses().get(0);
                if ("9".equals(status)) {
                    query.addCriteria(Criteria.where("refundStatus").in(Arrays.asList("1", "2")));
                }
            }
        } else {
            query.addCriteria(Criteria.where("status").ne("0"));
        }
        Date date = new Date();
        Criteria criteria = Criteria.where("payTime");
        Long a = 180 * 24 * 3600 * 1000L;
        criteria.gte(new Date(date.getTime() - a));
        log.info(":>>> 订单区间:{},{}", date, new Date(date.getTime() - a));
        criteria.lte(date);
        query.addCriteria(criteria);
        query.addCriteria(Criteria.where("writeOffed").ne(Boolean.TRUE));
        log.info(":>>> 订单列表查询:{}", JSON.toJSONString(query, SerializerFeature.IgnoreNonFieldGetter));
        long count = mongoTemplate.count(query, OrderInfo.class);
        PageRequest pageRequest = PageRequest.of(req.getPage() - 1, req.getPageSize());
//        query.with(new Sort(Sort.Direction.DESC, "createdTime"));
        Sort sort = Sort.by(Sort.Direction.DESC, "createdTime");
        query.with(sort);
        List<OrderInfo> infos = mongoTemplate.find(query.with(pageRequest), OrderInfo.class);
        List<OrderInfo> res = new ArrayList<>();
        List<String> orderIds = new ArrayList<>();
        HashMap<String, ActivityInfo> activityInfoCache = new HashMap<>();
        if (!CollectionUtils.isEmpty(infos)) {
            for (OrderInfo orderInfo : infos) {
                ActivityInfo activityInfo = null;
                if (!"1".equals(orderInfo.getStatus())) {
                    orderInfo.setCanModifyAddress(false);
                    orderInfo.setCanRefund(false);
                    //2021-08-27 17:59:28 之前下单不能退款
                } else if (Objects.nonNull(orderInfo.getPayTime()) && orderInfo.getPayTime().getTime() <= 1630056628000L) {
                    orderInfo.setCanModifyAddress(false);
                    orderInfo.setCanRefund(false);
                } else {
                    if (StringUtils.isNotBlank(orderInfo.getActivityId())) {
                        if (activityInfoCache.containsKey(orderInfo.getActivityId())) {
                            activityInfo = activityInfoCache.get(orderInfo.getActivityId());
                        } else {
                            Query query1 = new Query().addCriteria(Criteria.where("id").is(orderInfo.getActivityId()));
                            activityInfo = mongoTemplate.findOne(query1, ActivityInfo.class);
                            if (Objects.nonNull(activityInfo)) {
                                activityInfoCache.put(orderInfo.getActivityId(), activityInfo);
                            }
                        }
                        if (Objects.nonNull(activityInfo)) {
                            orderInfo.setCanModifyAddress(activityInfo.getCanModifyAddress());
                            orderInfo.setCanRefund(activityInfo.getCanRefund());

                        }
                    }
                }
                if (Objects.nonNull(activityInfo)) {
                    orderInfo.setCustomerService(activityInfo.getCustomerService());
                    orderInfo.setOpenAfterSales(activityInfo.getOpenAfterSales());
                    orderInfo.setAfterSalesInfos(activityInfo.getAfterSalesInfos());
                } else {
                    if (StringUtils.isNotBlank(orderInfo.getActivityId())) {
                        activityInfo = cacheActivityService.findById(orderInfo.getActivityId());
                    }
                    if (Objects.nonNull(activityInfo)) {
                        orderInfo.setCustomerService(activityInfo.getCustomerService());
                        orderInfo.setOpenAfterSales(activityInfo.getOpenAfterSales());
                        orderInfo.setAfterSalesInfos(activityInfo.getAfterSalesInfos());
                    }
                }
                //退款中 、退款已完成、已发货 、已收获后不显示订单发货提示语
                String status = orderInfo.getStatus();
                if ("6".equals(status) || "9".equals(status) || "4".equals(status) || "5".equals(status)) {
                    orderInfo.setTips("");
                }
//                orderInfo.setPostController(checkOrderPostController(orderInfo.getOrderNo(), orderInfo.getStatus(),
//                        orderInfo.getPayTime()));

                if (StringUtils.isNotBlank(orderInfo.getOrderNo())) {
                    Query query1 = new Query().addCriteria(Criteria.where("orderNo").is(orderInfo.getOrderNo()));
                    List<OOrderInfo> subOrderInfos = mongoTemplate.find(query1, OOrderInfo.class);
                    if (!CollectionUtils.isEmpty(subOrderInfos)) {
                        if ("4".equals(status)) {
                            Set<String> logisticsNumberSet = subOrderInfos.stream().filter(subOrderInfo -> "4".equals(subOrderInfo.getStatus())).map(OOrderInfo::getLogisticsNo).collect(Collectors.toSet());
                            if (logisticsNumberSet.size() == 1) {
                                OOrderInfo subOrderInfo = subOrderInfos.get(0);
                                if (!StringUtils.isBlank(subOrderInfo.getLogisticsNo()) && Objects.nonNull(subOrderInfo.getShippingTime())) {
                                    SubscribePushData subscribePushData = kuaiDi100Service.lastLogisticsResult(subOrderInfo.getLogisticsNo(), subOrderInfo.getOrderNo(), subOrderInfo.getShippingTime());
                                    if (Objects.nonNull(subscribePushData)) {
                                        orderInfo.setLastLogisticsResult(subscribePushData);
                                    }
                                }
                            }
                        }
                        boolean copyInfo = isNeedCopyLogisticsInfo(orderInfo, subOrderInfos);
                        log.info(":>>> 订单:{} 是否需要复制物流信息:{}", orderInfo.getOrderNo(), copyInfo);
                        for (OOrderInfo oOrderInfo : subOrderInfos) {
                            //2021-10-22 00:00:00 之前下的单子需要复制主订单的物流信息和状态
//                            if (Objects.nonNull(orderInfo.getPayTime()) && orderInfo.getPayTime().before(new Date
//                            (1634832000000L))) {
                            if (copyInfo) {
                                if (StringUtils.isNotBlank(orderInfo.getLogisticsNo()) && StringUtils.isBlank(oOrderInfo.getLogisticsNo())) {
                                    oOrderInfo.setLogisticsNo(orderInfo.getLogisticsNo());
                                    log.info(":>>> 子订单:{} 物流编号为空, 复制主订单的:{} --->:{} ", oOrderInfo.getOOrderNo(), orderInfo.getOrderNo(), orderInfo.getLogisticsNo());
                                }
                                if (StringUtils.isNotBlank(orderInfo.getLogisticsCompany()) && StringUtils.isBlank(oOrderInfo.getLogisticsCompany())) {
                                    oOrderInfo.setLogisticsCompany(orderInfo.getLogisticsCompany());
                                    log.info(":>>> 子订单:{} 物流公司为空, 复制主订单的:{} --->:{} ", oOrderInfo.getOOrderNo(), orderInfo.getOrderNo(), orderInfo.getLogisticsCompany());
                                }
                            }
//                            }
                            if (StringUtils.isNotBlank(orderInfo.getStatus()) && StringUtils.isBlank(oOrderInfo.getStatus())) {
                                oOrderInfo.setStatus(orderInfo.getStatus());
                            }
                            if (StringUtils.isNotBlank(orderInfo.getTips()) && StringUtils.isBlank(oOrderInfo.getTips())) {
                                oOrderInfo.setTips(orderInfo.getTips());
                            }
                            if ("3".equals(oOrderInfo.getStatus())) {
                                oOrderInfo.setStatus("2");
                            }
                        }
                        //子订单中包含如果只有"4"待收货情况变更为主订单为待收货
                        long subCount = subOrderInfos.stream().filter(subOrderInfo -> "4".equals(subOrderInfo.getStatus())).count();
                        if (subCount > 0) {
                            orderInfo.setStatus("4");
                        } else {
                            //子订单中只包含如果只有"3"待收货情况变更为定制中
                            subCount = subOrderInfos.stream().filter(subOrderInfo -> "3".equals(subOrderInfo.getStatus())).count();
                            if (subCount > 0) {
                                orderInfo.setStatus("2");
                            }
                        }
                    }
                    if ("3".equals(orderInfo.getStatus())) {
                        orderInfo.setStatus("2");
                    }
                    orderInfo.setOOrderInfos(subOrderInfos);
                }
                //兼容老数据，如果是订单中是只有礼品的，前端不展示出姓名、学校
                if ("ca".equals(orderInfo.getCategory()) && !CollectionUtils.isEmpty(orderInfo.getOOrderInfos())) {
                    //如果订单中无证书
                    long caCount = orderInfo.getOOrderInfos().stream().filter(oOrderInfo -> !oOrderInfo.getCaGift()).count();
                    if (caCount == 0) {
                        orderInfo.setCategory("gift");
                    }
                }
                orderInfoTipService.setSubOrderTips(orderInfo);
                if (Objects.nonNull(activityInfo)) {
                    orderInfo.setRefundConfirmUrl(activityInfo.getRefundConfirmUrl());
                    orderInfo.setShowRefundConfirmUrl(activityInfo.getShowRefundConfirmUrl());
                }
                if (!orderIds.contains(orderInfo.getId())) {
                    orderIds.add(orderInfo.getId());
                    res.add(orderInfo);
                }


            }
            /**
             * 此处只针对小程序下的订单退款
             */
            if ("wechat-mini".equals(req.getPlatform())) {
                for (OrderInfo orderInfo : res) {
                    if ("1".equals(orderInfo.getStatus()) && "wechat-mini".equals(orderInfo.getPlatform())) {
                        if (Objects.nonNull(orderInfo.getPayTime()) && ((System.currentTimeMillis() - orderInfo.getPayTime().getTime()) <= 12 * 3600 * 1000L)) {
                            orderInfo.setCanRefund(true);
                            log.info(":>>> 小程序订单:{},满足退款要求", orderInfo.getOrderNo());
                        }
                    }
                }
            }
        }
        log.info(":>>> 证书的订单列表信息大小:{}", res.size());
        return PageableExecutionUtils.getPage(res, pageRequest, () -> count);
    }

    @Override
    public Integer checkItemStock(ItemCheckStockReq req) {
        String itemId = req.getItemId();
        Integer num = req.getNum();
        UserPO currentUser = req.getCurrentUser();
        log.info("【校验商品库存】itemId:{},num:{},userId:{}", itemId, num, currentUser.getId());
        CaInfo caInfo = mongoTemplate.findById(itemId, CaInfo.class);
        if (Objects.isNull(caInfo)) {
            return 0;
        }
        List<String> itemMaterialList = caInfo.getItemMaterialList();
        if (CollectionUtils.isEmpty(itemMaterialList)) {
            return 0;
        }
        String itemMaterialId = itemMaterialList.get(0);
        Integer stockNum = caMaterialConfigService.getStockById(itemMaterialId);
        log.info("【校验商品库存】itemId:{},num:{},itemMaterialId:{}", itemId, stockNum, itemMaterialId);
        return stockNum;
    }

    /**
     * status 状态,0:待付款,1:已付款,2:制作中,3:待发货,4:待收货,5:已收货,6:订单完成,7:订单关闭,8:售后中,9:部分已发货
     * refundStatus 退款状态,0:未退款,1:退款申请,2:退款中,3:退款完成,4:待返货,7:部分退款中
     */

    private void setOrderTips(OrderInfo orderInfo) {
        if (Objects.isNull(orderInfo) || StringUtils.isBlank(orderInfo.getStatus())) {
            return;
        }
        String tips = "";
        if (StringUtils.isNotBlank(orderInfo.getRefundStatus())) {
            switch (orderInfo.getRefundStatus()) {
                case "2":
                    tips = "退款申请成功，原订单金额将于1-3个工作日到账，注意查收！";
                    orderInfo.setTips(tips);
                    return;
                case "3":
                    tips = "用户申请退款,退款完成,请查看微信账单!";
                    orderInfo.setTips(tips);
                    return;
                default:
                    break;
            }
        }

        if ("1".equals(orderInfo.getStatus())) {
            tips = "亲，您的订单需经过审核、制作、工艺加工、包装出库等流程。周期一般为5-7个工作日，请耐心等待，发货后会有物流单号在这里显示哦~";
            if (Objects.nonNull(orderInfo.getPayTime())) {
//                Date d = TimeUtils.getDayEndTime(orderInfo.getPayTime());
//                Date d = new Date(orderInfo.getPayTime().getTime() + 12 * 3600 * 1000L);
                if ((new Date().getTime() - orderInfo.getPayTime().getTime()) > 12 * 3600 * 1000L) {
                    orderInfo.setStatus("2");
                    tips = "亲，您的订单目前正在专属定制中，需经过审核、制作、工艺加工、包装出库等流程。周期一般为5-7个工作日，请耐心等待，发货后会有物流单号在这里显示哦~";
                }
            }
            OrderInfoTip orderInfoTip = orderInfoTipService.find(orderInfo.getOrderNo());
            if (Objects.nonNull(orderInfoTip) && StringUtils.isNotBlank(orderInfoTip.getTips())) {
                tips = orderInfoTip.getTips();
                log.info(":>>> 订单:{}在 提示语言信息中", orderInfo.getOrderNo(), tips);
            }

        } else if ("2".equals(orderInfo.getStatus())) {
            tips = "亲，您的订单目前正在专属定制中，需经过审核、制作、工艺加工、包装出库等流程。周期一般为5-7个工作日，请耐心等待，发货后会有物流单号在这里显示哦~";

        } else if ("3".equals(orderInfo.getStatus())) {
            tips = "亲，您的订单目前正在专属定制中，需经过审核、制作、工艺加工、包装出库等流程。周期一般为5-7个工作日，请耐心等待，发货后会有物流单号在这里显示哦~";

        } else if ("4".equals(orderInfo.getStatus())) {
            OrderInfoTip orderInfoTip = orderInfoTipService.find(orderInfo.getOrderNo(), Boolean.TRUE);
            if (Objects.nonNull(orderInfoTip) && StringUtils.isNotBlank(orderInfoTip.getTips())) {
                tips = orderInfoTip.getTips();
                log.info(":>>> 订单:{}在 提示语言信息中", orderInfo.getOrderNo(), tips);
            } else {
                tips = "您的订单已经发货，请注意查收！可点击下方按钮查看物流进度";
            }

        }
        orderInfo.setTips(tips);
    }

    /**
     * 设置子订单提示语
     *
     * @param orderInfo
     */
    private void setSubOrderTips(OrderInfo orderInfo) {
        if (Objects.isNull(orderInfo) || StringUtils.isBlank(orderInfo.getStatus()) || CollectionUtils.isEmpty(orderInfo.getOOrderInfos())) {
            log.info(":>>>  设置子订单编号错误:订单信息、订单状态、子订单集合为空");
            return;
        }
        for (OOrderInfo oOrderInfo : orderInfo.getOOrderInfos()) {
            CaInfo itemInfo = null;
            if (StringUtils.isNotBlank(oOrderInfo.getItemInfoId())) {
                Query queryItem = new Query().addCriteria(Criteria.where("id").is(oOrderInfo.getItemInfoId()));
                itemInfo = mongoTemplate.findOne(queryItem, CaInfo.class);
            }
            String tips = "";
            if (StringUtils.isNotBlank(orderInfo.getRefundStatus())) {
                switch (orderInfo.getRefundStatus()) {
                    case "2":
                        tips = "退款申请成功，原支付金额将于1-3个工作日到账，注意查收！";
                        oOrderInfo.setTips(tips);
                        return;
                    case "3":
                        tips = "用户申请退款,退款完成,请查看微信账单!";
                        oOrderInfo.setTips(tips);
                        return;
                    default:
                        break;
                }
            }
            // 状态,0:待付款,1:已付款,2:制作中,3:待发货,4:待收货,5:已收货,6:订单完成,7:订单关闭,8:售后中,9:退款中,10:部分已发货
            if ("1".equals(orderInfo.getStatus())) {
                tips = "亲，您的订单需经过审核、制作、工艺加工、包装出库等流程。周期一般为5-7个工作日，请耐心等待，发货后会有物流单号在这里显示哦~";
                if (Objects.nonNull(orderInfo.getPayTime())) {

                    if ((System.currentTimeMillis() - orderInfo.getPayTime().getTime()) > 12 * 3600 * 1000L) {
                        orderInfo.setStatus("2");
                        tips = "亲，您的订单目前正在专属定制中，需经过审核、制作、工艺加工、包装出库等流程。周期一般为5-7个工作日，请耐心等待，发货后会有物流单号在这里显示哦~";
                    }
                }
                if (Objects.nonNull(itemInfo)) {
                    setSubOrderTips2(itemInfo, oOrderInfo, tips);
                }
                OrderInfoTip orderInfoTip = orderInfoTipService.find(orderInfo.getOrderNo(), oOrderInfo.getOOrderNo());
                if (Objects.nonNull(orderInfoTip) && StringUtils.isNotBlank(orderInfoTip.getTips())) {
                    tips = orderInfoTip.getTips();
                    log.info(":>>> 订单:{}在 提示语言信息中", orderInfo.getOrderNo(), tips);
                }

            } else if ("2".equals(orderInfo.getStatus())) {
                tips = "亲，您的订单目前正在专属定制中，需经过审核、制作、工艺加工、包装出库等流程。周期一般为5-7个工作日，请耐心等待，发货后会有物流单号在这里显示哦~";
                if (Objects.nonNull(itemInfo)) {
                    setSubOrderTips2(itemInfo, oOrderInfo, tips);
                }
            } else if ("3".equals(orderInfo.getStatus())) {
                tips = "亲，您的订单目前正在专属定制中，需经过审核、制作、工艺加工、包装出库等流程。周期一般为5-7个工作日，请耐心等待，发货后会有物流单号在这里显示哦~";
                if (Objects.nonNull(itemInfo)) {
                    setSubOrderTips2(itemInfo, oOrderInfo, tips);
                }
            } else if ("4".equals(orderInfo.getStatus())) {
                OrderInfoTip orderInfoTip = orderInfoTipService.find(orderInfo.getOrderNo(), oOrderInfo.getOOrderNo(), Boolean.TRUE);
                if (Objects.nonNull(orderInfoTip) && StringUtils.isNotBlank(orderInfoTip.getTips())) {
                    tips = orderInfoTip.getTips();
                    log.info(":>>> 订单:{}在 提示语言信息中", orderInfo.getOrderNo(), tips);
                } else {
                    if (StringUtils.isNotBlank(oOrderInfo.getLogisticsNo())) {
                        tips = "您的订单已经发货，请注意查收！可点击下方按钮查看物流进度";
                    }
                }

            }
            oOrderInfo.setTips(tips);
        }
    }

    /**
     * 按照指定的格式返回日期字符串. 默认 "yyyy-MM-dd"
     *
     * @param date
     * @param pattern
     * @return
     */
    public static String formatDate(Date date, String pattern) {
        if (date == null) return "";
        if (pattern == null) pattern = "yyyy-MM-dd";
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return (sdf.format(date));
    }

    /**
     * 保存证书订单
     *
     * @param user
     * @param req
     * @return
     */
    protected OrderPO saveUserCaOrder(UserPO user, PlaceOrderReq req) {
        log.info("saveOrder userId {} applyReq {}", user.getId(), req);
        Query query = new Query().addCriteria(Criteria.where("id").is(req.getUserCaInfoId()));
        UserCaInfo userCaInfo = mongoTemplate.findOne(query, UserCaInfo.class);
        if (Objects.isNull(userCaInfo)) {
            log.error(":>>> 用户证书订单不存在:{}", req.getUserCaInfoId());
            throw new BusinessException("用户证书订单不存在");
        }
        OrderPO orderPO = new OrderPO();
        // goodsCode对应证书编码
        orderPO.setOrderNo(req.getOrderNo());
        orderPO.setSource(req.getSource());
        orderPO.setPayType(OrderPayTypeEnum.WX.getCode());
        GoodsInfo goods = new GoodsInfo();
        goods.setGoodsName(userCaInfo.getCaInfo().getName());
        orderPO.setGoods(goods);
        orderPO.setPayPrice(req.getPrice());
        orderPO.setTotalPrice(req.getPrice());
        orderPO.setClientIp(req.getClientIp());
        orderPO.setPlatform(user.getCurrentPlatform());
        orderPO.setOpenId(user.getOpenId());
        return orderPO;
    }

    /**
     * @param choicedMemberShip:是否选择会员
     * @param memberShiped:本身是否已经是会员
     * @param memberShipRemainNum:可支付的次数
     * @param remainNum:剩余支付的次数
     * @param userId:用户ID
     * @param memberShipPrice:会员卡价格
     * @param caInfos:证书信息
     * @return
     */
    private Integer computeOrderPrice(Boolean choicedMemberShip, Boolean memberShiped, Integer memberShipRemainNum, Integer remainNum, String userId, Integer memberShipPrice, List<CaInfo> caInfos) {
        log.info(":>>> 开始计算用户下单价格userId:{},choicedMemberShip:{},memberShiped:{},memberShipRemainNum:{}," + ":remainNum:{},memberShipPrice:{}", userId, choicedMemberShip, memberShiped, memberShipRemainNum, remainNum, memberShipPrice);
        Integer price = 0;
        if (Boolean.TRUE.equals(choicedMemberShip)) {
            log.info(":>>> 用户选择的会员卡:{}", userId);
            if (!Boolean.TRUE.equals(memberShiped)) {
                log.info(":>>> 用户:{} 本身不是会员", userId);
                remainNum = memberShipRemainNum;
                price = memberShipPrice;
            } else {
                log.info(":>>> 用户:{} 本身是会员", userId);
            }

            for (CaInfo caInfo : caInfos) {
                log.info(":>>> 证书:{} -> 剩余抵扣次数:{} -> 价格:{}", caInfo.getName(), remainNum, caInfo.getPrice());
                // 会员卡抵扣
                if (remainNum <= 0) {
                    price = price + caInfo.getPrice();
                }
                remainNum--;
            }
            log.info(":>>> 用户:{},提交订单生成的价格为:{}", userId, price);

        } else {
            log.info(":>>> 用户没有选择的会员卡:{}", userId);
            for (CaInfo caInfo : caInfos) {
                // 生成证书订单
                log.info(":>>> 证书:{} -> 价格:{}", caInfo.getName(), caInfo.getPrice());
                price = price + caInfo.getPrice();

            }
        }
        return price;
    }

    /**
     * 设置退款和修改地址状态
     */
    private void setRefundAndMofityAddress(OrderInfo orderInfo) {
        if (!"1".equals(orderInfo.getStatus())) {
            orderInfo.setCanModifyAddress(false);
            orderInfo.setCanRefund(false);
            log.info(":>>> 订单:{} 状态:{},不为已付款和定制中，不能退款和修改地址", orderInfo.getOrderNo(), orderInfo.getStatus());
            //2021-08-27 17:59:28 之前下单不能退款
        } else if (Objects.nonNull(orderInfo.getPayTime()) && orderInfo.getPayTime().getTime() <= 1630056628000L) {
            orderInfo.setCanModifyAddress(false);
            orderInfo.setCanRefund(false);
            log.info(":>>> 订单:{} 支付时间:{},在2021-08-27 17:59:28 之前下单不能退款", orderInfo.getOrderNo(), orderInfo.getPayTime());
        } else {
            if (StringUtils.isNotBlank(orderInfo.getActivityId())) {
                Query query1 = new Query().addCriteria(Criteria.where("id").is(orderInfo.getActivityId()));
                ActivityInfo activityInfo = mongoTemplate.findOne(query1, ActivityInfo.class);
                if (Objects.nonNull(activityInfo)) {

                    orderInfo.setCanModifyAddress(activityInfo.getCanModifyAddress());
                    orderInfo.setCanRefund(activityInfo.getCanRefund());
                }
            }
        }
    }

    /**
     * 获取邮费模版
     *
     * @param postageTemplate
     * @param province
     * @param expreeFee
     * @return
     */
    private HashMap<String, Integer> getOrderExpreeFee(PostageTemplate postageTemplate, String province, Integer expreeFee) {
        log.info(":>>> 开始获取省:{},邮费:{},模版:{}", province, expreeFee, JSON.toJSONString(postageTemplate));
        HashMap<String, Integer> res = new HashMap<>();
        if (StringUtils.isBlank(province) || Objects.isNull(postageTemplate)) {
            log.error(":>>> 下单参数错误:省或证书邮费配置为空");
            res.put("fee", 0);
            res.put("extraFee", 0);
//            throw new BusinessException("请联系客服领取!");
        }
        Integer fee = 0;
        Integer extraFee = 0;
        Query query = new Query().addCriteria(Criteria.where("postageTemplateId").is(postageTemplate.getId()).and("province").is(province));
        PostageTemplateDetail p = mongoTemplate.findOne(query, PostageTemplateDetail.class);
        log.info(">>> 偏远地区邮费:{}", JSON.toJSONString(p));
        if (Objects.nonNull(p)) {
            extraFee = p.getPrice().intValue();

        }
        if (Objects.nonNull(expreeFee)) {
            if (expreeFee.compareTo(0) == 1) {
                fee = expreeFee;
            } else {
                fee = postageTemplate.getPrice().intValue();
            }

        } else {
            fee = postageTemplate.getPrice().intValue();
        }
        res.put("fee", fee);
        res.put("extraFee", extraFee);
        return res;
    }

    /**
     * 是否复制物流信息
     *
     * @param orderInfo
     * @param subOrders
     * @return
     */
    private boolean isNeedCopyLogisticsInfo(OrderInfo orderInfo, List<OOrderInfo> subOrders) {
        if (Objects.isNull(orderInfo) || CollectionUtils.isEmpty(subOrders)) {
            return false;
        }
        if (!StringUtils.isBlank(orderInfo.getLogisticsNo())) {
            for (OOrderInfo oOrderInfo : subOrders) {
                if (StringUtils.isNotBlank(oOrderInfo.getLogisticsNo())) {
                    return false;
                }
            }
            return true;

        }
        return false;

    }

    private OOrderInfo buildOOrderInfo(CaInfo caInfo, UserPO userPO, String activityId, String orderNo, String oorderNo, boolean gift, Integer num) {
        OOrderInfo oOrderInfo = new OOrderInfo();
        oOrderInfo.setOrderNo(orderNo);
        oOrderInfo.setOOrderNo(oorderNo);
        oOrderInfo.setCreatedTime(new Date());
        oOrderInfo.setAccountInfoId(userPO.getId());
        if (ArrayUtils.isEmpty(caInfo.getCertificateImages())) {
            oOrderInfo.setImageUrl(caInfo.getCertificateImage());
        } else {
            oOrderInfo.setImageUrl(caInfo.getCertificateImages()[0]);
        }
        List<String> itemMaterialIdList = caInfo.getItemMaterialList();
        if (!CollectionUtils.isEmpty(itemMaterialIdList)) {
            long count = itemMaterialIdList.stream().filter(itemMaterialId -> caMaterialConfigService.overbought(itemMaterialId)).count();
            if (count > 0) {//超卖
                oOrderInfo.setOverbought(Boolean.TRUE);
            } else {
                List<CaMaterialConfig> materialList = caMaterialConfigService.findByCaMaterialIdList(itemMaterialIdList);
                long stockCountZero = materialList.stream().filter(caMaterialConfig -> (caMaterialConfig.getStockCount() - caMaterialConfig.getSoldCount()) <= 0).count();
                if (stockCountZero > 0) {
                    oOrderInfo.setOverbought(Boolean.TRUE);
                }
            }
        }
        //如果礼品
        if (2 == caInfo.getItemType() && num >= 2) {
            if (!CollectionUtils.isEmpty(itemMaterialIdList)) {
                String itemMaterialId = itemMaterialIdList.get(0);
                Boolean overbought = caMaterialConfigService.overboughtByIdAndNum(itemMaterialId, num);
                if (!caInfo.getCanOverbought()) {
                    log.info("商品礼品设置不超卖 itemId:{},num:{},userId:{},是否超卖:{}", caInfo.getId(), num, userPO.getId(), overbought);
                    if (overbought) {
                        throw new BusinessException("库存不足");
                    }
                } else {
                    //允许超卖情况
                    if (overbought) {
                        oOrderInfo.setOverbought(Boolean.TRUE);
                    }
                }
            }
        }
        if (Objects.nonNull(caInfo.getItemType())) {
            switch (caInfo.getItemType()) {
                case 1:
                    oOrderInfo.setItemType("ca");
                    break;
                case 2:
                    oOrderInfo.setItemType("item");
                    break;
                case 3:
                    oOrderInfo.setItemType("ca");
                    break;
                default:
                    break;
            }
        }
        oOrderInfo.setCaInfo(caInfo);
        oOrderInfo.setCaItemType(caInfo.getItemType());
        oOrderInfo.setItemInfoId(caInfo.getId());
        oOrderInfo.setStatus("0");
        oOrderInfo.setItemTitle(caInfo.getName());
        if (ArrayUtils.isEmpty(caInfo.getCertificateImages())) {
            oOrderInfo.setItemImageUrl(caInfo.getCertificateImage());
        } else {
            oOrderInfo.setItemImageUrl(caInfo.getCertificateImages()[0]);
        }
        oOrderInfo.setSalePrice(caInfo.getPrice());
        oOrderInfo.setTotalFee(Math.multiplyExact(caInfo.getPrice(), num));
        oOrderInfo.setItemPrice(caInfo.getPrice());
        oOrderInfo.setAppId(userPO.getAppId());
        oOrderInfo.setOpenId(userPO.getOpenId());
        oOrderInfo.setExpressFee(caInfo.getExpressFee().toString());
        oOrderInfo.setPlatform("wechat-h5");
        if (2 == caInfo.getItemType()) {
            oOrderInfo.setCaGift(Boolean.TRUE);
        } else {
            oOrderInfo.setCaGift(Boolean.FALSE);
        }
        oOrderInfo.setNum(num);
        oOrderInfo.setOpenId(userPO.getOpenId());
        oOrderInfo.setActivityId(activityId);
        oOrderInfo.setGift(caInfo.getGift());
        oOrderInfo.setStatus("0");
        if (gift) {
            oOrderInfo.setGifted(true);
            oOrderInfo.setSalePrice(0);
            oOrderInfo.setItemPrice(0);
            oOrderInfo.setSalePriceBack(caInfo.getPrice());
            oOrderInfo.setItemPriceBack(caInfo.getOriginalPrice());
            oOrderInfo.setItemPrice(0);
        } else {
            oOrderInfo.setGifted(false);
        }
        boolean hasVirtualGoods = caInfo.getHasVirtualGoods() == null ? false : caInfo.getHasVirtualGoods();
        oOrderInfo.setHasVirtualGoods(hasVirtualGoods);
        if (hasVirtualGoods) {
            String goodsId = caInfo.getVirtualGoodsList();
            oOrderInfo.setVirtualGoodsId(goodsId);
            VipGoods goods = mongoTemplate.findById(goodsId, VipGoods.class);
            if (goods != null) {
                oOrderInfo.setVirtualGoodsName(goods.getProductName() + "（" + goods.getExpireDay() + "天内有效）");
                oOrderInfo.setVirtualGoodsCode(goods.getProductId());
            }
        }
        return oOrderInfo;
    }

    /**
     * 检查下单时间
     *
     * @param activityId
     */
    private void checkPlaceOrderTime(String activityId, Date date) {
        Query query = new Query().addCriteria(Criteria.where("activityId").is(activityId));
        PayConfigPage config = mongoTemplate.findOne(query, PayConfigPage.class);
        if (Objects.isNull(config)) {
            log.info(":>>> 活动收款:{} 为空", activityId);
            return;
        }
        if (Objects.nonNull(config.getPayStartTime()) && date.before(config.getPayStartTime())) {
            log.error(":>>> 收款开始时间为:{},当前时间为:{},收款未开始", config.getPayStartTime(), date);
            throw new BusinessException("未到领取时间,请联系客服!");

        }
        if (Objects.nonNull(config.getPayEndTime()) && date.after(config.getPayEndTime())) {
            log.error(":>>> 收款结束时间为:{},当前时间为:{},收款已经结束", config.getPayEndTime(), date);
            throw new BusinessException("证书领取已经结束,请联系客服!");

        }

    }

    /**
     * 设置订单提示语,正对超卖订单
     *
     * @param itemInfo
     * @param oOrderInfo
     * @param tips
     */
    private void setSubOrderTips2(CaInfo itemInfo, OOrderInfo oOrderInfo, String tips) {
        if (Objects.nonNull(itemInfo)) {
            if (Boolean.TRUE.equals(oOrderInfo.getOverbought()) && StringUtils.isNotBlank(itemInfo.getNoStockTips())) {
                tips = itemInfo.getNoStockTips();
            } else {
                if (StringUtils.isNotBlank(itemInfo.getInStockTips())) {
                    tips = itemInfo.getInStockTips();
                }
            }
        }
    }

    /**
     * 检测该订单是否需要提示疫情管控
     *
     * @param orderNo
     * @param status
     * @param payTime
     * @return
     */
    private Boolean checkOrderPostController(String orderNo, String status, Date payTime) {
//        log.info("【订单管控提示】 orderNo:{},status:{},payTime:{}", orderNo, status, payTime);
//        //定制中才进行校验
//        if (Objects.isNull(payTime)) {
//            return Boolean.FALSE;
//        }
//        if (Lists.newArrayList("2","3").contains(status)){
//            int num = calLeaveDayService.getCalLeaveDaysNum(payTime,new Date());
//            log.info("订单管控提示 orderNo:{},payTime:{},now:{},day:{}", orderNo, payTime, new Date(), num);
//            if (num >= 5) {
//                return Boolean.TRUE;
//            }
//        }
        return Boolean.FALSE;
    }

}
